summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--firmware/zpu/apps/txrx_uhd.c53
-rw-r--r--firmware/zpu/lib/net_common.c25
-rw-r--r--fpga/usrp2/coregen/Makefile.srcs2
-rw-r--r--fpga/usrp2/coregen/coregen.cgp4
-rw-r--r--fpga/usrp2/coregen/fifo_generator_ug175.pdfbin2895895 -> 1069823 bytes
-rw-r--r--fpga/usrp2/coregen/fifo_xlnx_1Kx18_2clk.ngc3
-rw-r--r--fpga/usrp2/coregen/fifo_xlnx_1Kx18_2clk.v3819
-rw-r--r--fpga/usrp2/coregen/fifo_xlnx_1Kx18_2clk.veo47
-rw-r--r--fpga/usrp2/coregen/fifo_xlnx_1Kx18_2clk.xco82
-rw-r--r--fpga/usrp2/coregen/fifo_xlnx_1Kx18_2clk_fifo_generator_v4_3_xst_1.lso3
-rw-r--r--fpga/usrp2/coregen/fifo_xlnx_1Kx18_2clk_fifo_generator_v4_3_xst_1.ngc_xst.xrpt106
-rw-r--r--fpga/usrp2/coregen/fifo_xlnx_1Kx18_2clk_flist.txt8
-rw-r--r--fpga/usrp2/coregen/fifo_xlnx_1Kx18_2clk_readme.txt38
-rw-r--r--fpga/usrp2/coregen/fifo_xlnx_1Kx18_2clk_xmdf.tcl68
-rw-r--r--fpga/usrp2/fifo/fifo_2clock.v5
-rw-r--r--fpga/usrp2/gpmc/Makefile.srcs2
-rw-r--r--fpga/usrp2/gpmc/fifo_watcher.v7
-rw-r--r--fpga/usrp2/gpmc/gpmc_async.v62
-rw-r--r--fpga/usrp2/gpmc/new_read.v62
-rw-r--r--fpga/usrp2/gpmc/new_write.v82
-rw-r--r--fpga/usrp2/sdr_lib/Makefile.srcs8
-rw-r--r--fpga/usrp2/sdr_lib/add2_and_clip.v12
-rw-r--r--fpga/usrp2/sdr_lib/add2_and_clip_reg.v25
-rw-r--r--fpga/usrp2/sdr_lib/dsp_core_rx.v135
-rw-r--r--fpga/usrp2/sdr_lib/dsp_core_rx_tb.v73
-rw-r--r--fpga/usrp2/sdr_lib/dsp_core_tx.v24
-rw-r--r--fpga/usrp2/sdr_lib/hb_dec.v121
-rw-r--r--fpga/usrp2/sdr_lib/hb_dec_tb.v10
-rw-r--r--fpga/usrp2/sdr_lib/input.dat276
-rw-r--r--fpga/usrp2/sdr_lib/round.v4
-rw-r--r--fpga/usrp2/sdr_lib/round_reg.v13
-rw-r--r--fpga/usrp2/sdr_lib/round_sd.v22
-rw-r--r--fpga/usrp2/sdr_lib/round_sd_tb.v58
-rw-r--r--fpga/usrp2/sdr_lib/rx_dcoffset.v43
-rw-r--r--fpga/usrp2/sdr_lib/rx_dcoffset_tb.v20
-rw-r--r--fpga/usrp2/sdr_lib/rx_frontend.v73
-rw-r--r--fpga/usrp2/sdr_lib/rx_frontend_tb.v45
-rw-r--r--fpga/usrp2/sdr_lib/small_hb_dec.v70
-rw-r--r--fpga/usrp2/sdr_lib/tx_frontend.v86
-rw-r--r--fpga/usrp2/top/B100/u1plus_core.v146
-rw-r--r--fpga/usrp2/top/E1x0/Makefile.passthru98
-rwxr-xr-xfpga/usrp2/top/E1x0/core_compile2
-rw-r--r--fpga/usrp2/top/E1x0/passthru.ucf6
-rw-r--r--fpga/usrp2/top/E1x0/u1e.v38
-rw-r--r--fpga/usrp2/top/E1x0/u1e_core.v188
-rw-r--r--fpga/usrp2/top/N2x0/u2plus_core.v29
-rw-r--r--fpga/usrp2/top/USRP2/u2_core.v31
-rw-r--r--fpga/usrp2/vrt/vita_tx_chain.v4
-rw-r--r--host/CMakeLists.txt6
-rw-r--r--host/apps/omap_debug/usrp_e.h33
-rw-r--r--host/cmake/Modules/FindDocutils.cmake (renamed from host/Modules/FindDocutils.cmake)0
-rw-r--r--host/cmake/Modules/FindGit.cmake (renamed from host/Modules/FindGit.cmake)0
-rw-r--r--host/cmake/Modules/FindUSB1.cmake (renamed from host/Modules/FindUSB1.cmake)0
-rw-r--r--host/cmake/Modules/UHDComponent.cmake (renamed from host/Modules/UHDComponent.cmake)0
-rw-r--r--host/cmake/Modules/UHDPackage.cmake (renamed from host/Modules/UHDPackage.cmake)0
-rw-r--r--host/cmake/Modules/UHDPython.cmake (renamed from host/Modules/UHDPython.cmake)0
-rw-r--r--host/cmake/Modules/UHDVersion.cmake (renamed from host/Modules/UHDVersion.cmake)4
-rw-r--r--host/cmake/cmake_uninstall.cmake.in (renamed from host/cmake_uninstall.cmake.in)0
-rw-r--r--host/cmake/msvc/inttypes.h (renamed from host/msvc/inttypes.h)0
-rw-r--r--host/cmake/msvc/stdint.h (renamed from host/msvc/stdint.h)0
-rw-r--r--host/docs/images.rst1
-rw-r--r--host/docs/usrp1.rst20
-rw-r--r--host/docs/usrp2.rst56
-rw-r--r--host/docs/usrp_e1xx.rst15
-rw-r--r--host/examples/CMakeLists.txt2
-rw-r--r--host/examples/rx_multi_samples.cpp2
-rw-r--r--host/examples/test_messages.cpp (renamed from host/examples/test_async_messages.cpp)140
-rw-r--r--host/include/uhd/CMakeLists.txt2
-rw-r--r--host/include/uhd/property_tree.hpp143
-rw-r--r--host/include/uhd/property_tree.ipp95
-rw-r--r--host/include/uhd/types/serial.hpp27
-rw-r--r--host/include/uhd/usrp/CMakeLists.txt10
-rw-r--r--host/include/uhd/usrp/codec_props.hpp42
-rw-r--r--host/include/uhd/usrp/dboard_base.hpp37
-rw-r--r--host/include/uhd/usrp/dboard_eeprom.hpp2
-rw-r--r--host/include/uhd/usrp/dboard_manager.hpp6
-rw-r--r--host/include/uhd/usrp/dboard_props.hpp43
-rw-r--r--host/include/uhd/usrp/dsp_props.hpp50
-rw-r--r--host/include/uhd/usrp/dsp_utils.hpp96
-rw-r--r--host/include/uhd/usrp/mboard_eeprom.hpp2
-rw-r--r--host/include/uhd/usrp/mboard_iface.hpp16
-rw-r--r--host/include/uhd/usrp/mboard_props.hpp56
-rw-r--r--host/include/uhd/usrp/misc_utils.hpp71
-rw-r--r--host/include/uhd/usrp/subdev_props.hpp64
-rw-r--r--host/include/uhd/usrp/subdev_spec.hpp5
-rw-r--r--host/include/uhd/usrp/tune_helper.hpp78
-rw-r--r--host/include/uhd/utils/CMakeLists.txt1
-rw-r--r--host/include/uhd/utils/tasks.hpp53
-rw-r--r--host/lib/CMakeLists.txt1
-rw-r--r--host/lib/property_tree.cpp132
-rw-r--r--host/lib/transport/libusb1_base.cpp2
-rw-r--r--host/lib/transport/libusb1_control.cpp3
-rw-r--r--host/lib/transport/libusb1_zero_copy.cpp34
-rw-r--r--host/lib/transport/super_recv_packet_handler.hpp113
-rw-r--r--host/lib/transport/super_send_packet_handler.hpp11
-rw-r--r--host/lib/usrp/CMakeLists.txt8
-rw-r--r--host/lib/usrp/b100/CMakeLists.txt17
-rw-r--r--host/lib/usrp/b100/b100_ctrl.cpp170
-rw-r--r--host/lib/usrp/b100/b100_ctrl.hpp19
-rw-r--r--host/lib/usrp/b100/b100_iface.cpp336
-rw-r--r--host/lib/usrp/b100/b100_iface.hpp73
-rw-r--r--host/lib/usrp/b100/b100_impl.cpp367
-rw-r--r--host/lib/usrp/b100/b100_impl.hpp202
-rw-r--r--host/lib/usrp/b100/b100_regs.hpp161
-rw-r--r--host/lib/usrp/b100/clock_ctrl.cpp21
-rw-r--r--host/lib/usrp/b100/clock_ctrl.hpp8
-rw-r--r--host/lib/usrp/b100/codec_ctrl.cpp10
-rw-r--r--host/lib/usrp/b100/codec_ctrl.hpp6
-rw-r--r--host/lib/usrp/b100/codec_impl.cpp149
-rw-r--r--host/lib/usrp/b100/ctrl_packet.hpp2
-rw-r--r--host/lib/usrp/b100/dboard_iface.cpp61
-rw-r--r--host/lib/usrp/b100/dboard_impl.cpp185
-rw-r--r--host/lib/usrp/b100/dsp_impl.cpp189
-rw-r--r--host/lib/usrp/b100/io_impl.cpp249
-rw-r--r--host/lib/usrp/b100/mboard_impl.cpp246
-rw-r--r--host/lib/usrp/common/CMakeLists.txt (renamed from host/lib/usrp/fx2/CMakeLists.txt)10
-rw-r--r--host/lib/usrp/common/fx2_ctrl.cpp (renamed from host/lib/usrp/fx2/fx2_ctrl.cpp)50
-rw-r--r--host/lib/usrp/common/fx2_ctrl.hpp (renamed from host/lib/usrp/fx2/fx2_ctrl.hpp)11
-rw-r--r--host/lib/usrp/common/recv_packet_demuxer.cpp87
-rw-r--r--host/lib/usrp/common/recv_packet_demuxer.hpp41
-rw-r--r--host/lib/usrp/common/validate_subdev_spec.cpp73
-rw-r--r--host/lib/usrp/common/validate_subdev_spec.hpp (renamed from host/include/uhd/usrp/device_props.hpp)33
-rw-r--r--host/lib/usrp/cores/CMakeLists.txt32
-rw-r--r--host/lib/usrp/cores/i2c_core_100.cpp138
-rw-r--r--host/lib/usrp/cores/i2c_core_100.hpp (renamed from fpga/usrp2/top/E1x0/passthru.v)34
-rw-r--r--host/lib/usrp/cores/rx_dsp_core_200.cpp202
-rw-r--r--host/lib/usrp/cores/rx_dsp_core_200.hpp61
-rw-r--r--host/lib/usrp/cores/rx_frontend_core_200.cpp61
-rw-r--r--host/lib/usrp/cores/rx_frontend_core_200.hpp42
-rw-r--r--host/lib/usrp/cores/spi_core_100.cpp88
-rw-r--r--host/lib/usrp/cores/spi_core_100.hpp35
-rw-r--r--host/lib/usrp/cores/time64_core_200.cpp132
-rw-r--r--host/lib/usrp/cores/time64_core_200.hpp61
-rw-r--r--host/lib/usrp/cores/tx_dsp_core_200.cpp140
-rw-r--r--host/lib/usrp/cores/tx_dsp_core_200.hpp51
-rw-r--r--host/lib/usrp/cores/tx_frontend_core_200.cpp70
-rw-r--r--host/lib/usrp/cores/tx_frontend_core_200.hpp42
-rw-r--r--host/lib/usrp/cores/wb_iface.hpp60
-rw-r--r--host/lib/usrp/dboard/db_basic_and_lf.cpp9
-rw-r--r--host/lib/usrp/dboard/db_dbsrx.cpp1
-rw-r--r--host/lib/usrp/dboard/db_dbsrx2.cpp1
-rw-r--r--host/lib/usrp/dboard/db_rfx.cpp1
-rw-r--r--host/lib/usrp/dboard/db_sbx.cpp1
-rw-r--r--host/lib/usrp/dboard/db_tvrx.cpp1
-rw-r--r--host/lib/usrp/dboard/db_tvrx2.cpp1
-rw-r--r--host/lib/usrp/dboard/db_unknown.cpp9
-rw-r--r--host/lib/usrp/dboard/db_wbx_common.cpp1
-rw-r--r--host/lib/usrp/dboard/db_wbx_simple.cpp1
-rw-r--r--host/lib/usrp/dboard/db_xcvr2450.cpp1
-rw-r--r--host/lib/usrp/dboard_eeprom.cpp2
-rw-r--r--host/lib/usrp/dboard_manager.cpp123
-rw-r--r--host/lib/usrp/dsp_utils.cpp141
-rw-r--r--host/lib/usrp/e100/CMakeLists.txt (renamed from host/lib/usrp/usrp_e100/CMakeLists.txt)21
-rw-r--r--host/lib/usrp/e100/clock_ctrl.cpp (renamed from host/lib/usrp/usrp_e100/clock_ctrl.cpp)37
-rw-r--r--host/lib/usrp/e100/clock_ctrl.hpp (renamed from host/lib/usrp/usrp_e100/clock_ctrl.hpp)10
-rw-r--r--host/lib/usrp/e100/codec_ctrl.cpp (renamed from host/lib/usrp/usrp_e100/codec_ctrl.cpp)38
-rw-r--r--host/lib/usrp/e100/codec_ctrl.hpp (renamed from host/lib/usrp/usrp_e100/codec_ctrl.hpp)10
-rw-r--r--host/lib/usrp/e100/dboard_iface.cpp (renamed from host/lib/usrp/usrp_e100/dboard_iface.cpp)151
-rw-r--r--host/lib/usrp/e100/e100_ctrl.cpp (renamed from host/lib/usrp/usrp_e100/usrp_e100_iface.cpp)230
-rw-r--r--host/lib/usrp/e100/e100_ctrl.hpp45
-rw-r--r--host/lib/usrp/e100/e100_impl.cpp390
-rw-r--r--host/lib/usrp/e100/e100_impl.hpp129
-rw-r--r--host/lib/usrp/e100/e100_mmap_zero_copy.cpp (renamed from host/lib/usrp/usrp_e100/usrp_e100_mmap_zero_copy.cpp)32
-rw-r--r--host/lib/usrp/e100/e100_regs.hpp157
-rw-r--r--host/lib/usrp/e100/fpga_downloader.cpp (renamed from host/lib/usrp/usrp_e100/fpga_downloader.cpp)14
-rw-r--r--host/lib/usrp/e100/include/linux/usrp_e.h (renamed from host/lib/usrp/usrp_e100/include/linux/usrp_e.h)33
-rw-r--r--host/lib/usrp/e100/io_impl.cpp327
-rw-r--r--host/lib/usrp/mboard_eeprom.cpp2
-rw-r--r--host/lib/usrp/misc_utils.cpp225
-rw-r--r--host/lib/usrp/multi_usrp.cpp365
-rw-r--r--host/lib/usrp/tune_helper.cpp147
-rw-r--r--host/lib/usrp/usrp1/CMakeLists.txt9
-rw-r--r--host/lib/usrp/usrp1/clock_ctrl.cpp68
-rw-r--r--host/lib/usrp/usrp1/clock_ctrl.hpp57
-rw-r--r--host/lib/usrp/usrp1/codec_ctrl.cpp26
-rw-r--r--host/lib/usrp/usrp1/codec_ctrl.hpp12
-rw-r--r--host/lib/usrp/usrp1/codec_impl.cpp159
-rw-r--r--host/lib/usrp/usrp1/dboard_iface.cpp23
-rw-r--r--host/lib/usrp/usrp1/dboard_impl.cpp218
-rw-r--r--host/lib/usrp/usrp1/dsp_impl.cpp222
-rw-r--r--host/lib/usrp/usrp1/io_impl.cpp288
-rw-r--r--host/lib/usrp/usrp1/mboard_impl.cpp407
-rw-r--r--host/lib/usrp/usrp1/soft_time_ctrl.cpp90
-rw-r--r--host/lib/usrp/usrp1/soft_time_ctrl.hpp11
-rw-r--r--host/lib/usrp/usrp1/usrp1_calc_mux.hpp156
-rw-r--r--host/lib/usrp/usrp1/usrp1_iface.cpp102
-rw-r--r--host/lib/usrp/usrp1/usrp1_iface.hpp24
-rw-r--r--host/lib/usrp/usrp1/usrp1_impl.cpp354
-rw-r--r--host/lib/usrp/usrp1/usrp1_impl.hpp162
-rw-r--r--host/lib/usrp/usrp2/CMakeLists.txt11
-rw-r--r--host/lib/usrp/usrp2/codec_impl.cpp181
-rw-r--r--host/lib/usrp/usrp2/dboard_impl.cpp183
-rw-r--r--host/lib/usrp/usrp2/dsp_impl.cpp262
-rw-r--r--host/lib/usrp/usrp2/fw_common.h14
-rw-r--r--host/lib/usrp/usrp2/io_impl.cpp257
-rw-r--r--host/lib/usrp/usrp2/mboard_impl.cpp490
-rw-r--r--host/lib/usrp/usrp2/usrp2_iface.cpp63
-rw-r--r--host/lib/usrp/usrp2/usrp2_iface.hpp14
-rw-r--r--host/lib/usrp/usrp2/usrp2_impl.cpp470
-rw-r--r--host/lib/usrp/usrp2/usrp2_impl.hpp191
-rw-r--r--host/lib/usrp/usrp2/usrp2_regs.hpp75
-rw-r--r--host/lib/usrp/usrp_e100/codec_impl.cpp149
-rw-r--r--host/lib/usrp/usrp_e100/dboard_impl.cpp185
-rw-r--r--host/lib/usrp/usrp_e100/dsp_impl.cpp190
-rw-r--r--host/lib/usrp/usrp_e100/io_impl.cpp315
-rw-r--r--host/lib/usrp/usrp_e100/mboard_impl.cpp222
-rw-r--r--host/lib/usrp/usrp_e100/usrp_e100_iface.hpp75
-rw-r--r--host/lib/usrp/usrp_e100/usrp_e100_impl.cpp217
-rw-r--r--host/lib/usrp/usrp_e100/usrp_e100_impl.hpp173
-rw-r--r--host/lib/usrp/usrp_e100/usrp_e100_regs.hpp221
-rw-r--r--host/lib/utils/CMakeLists.txt1
-rw-r--r--host/lib/utils/tasks.cpp75
-rw-r--r--host/tests/CMakeLists.txt2
-rw-r--r--host/tests/property_test.cpp175
-rw-r--r--host/tests/sph_recv_test.cpp3
-rw-r--r--host/tests/tune_helper_test.cpp251
-rw-r--r--host/usrp_e_utils/CMakeLists.txt8
-rw-r--r--host/usrp_e_utils/clkgen_config.hpp305
-rw-r--r--host/usrp_e_utils/usrp-e-debug-pins.c30
-rw-r--r--host/usrp_e_utils/usrp-e-gpio.c22
-rw-r--r--host/usrp_e_utils/usrp-e-i2c.c87
-rw-r--r--host/usrp_e_utils/usrp-e-spi.c54
-rw-r--r--host/usrp_e_utils/usrp-e-utility.cpp72
-rw-r--r--host/usrp_e_utils/usrp-e-wb-test.cpp22
-rw-r--r--host/utils/uhd_usrp_probe.cpp120
-rw-r--r--host/utils/usrp1_init_eeprom.cpp6
-rw-r--r--host/utils/usrp_burn_db_eeprom.cpp36
-rw-r--r--host/utils/usrp_burn_mb_eeprom.cpp11
-rw-r--r--images/Makefile2
229 files changed, 11805 insertions, 10124 deletions
diff --git a/firmware/zpu/apps/txrx_uhd.c b/firmware/zpu/apps/txrx_uhd.c
index 975ec58e2..5bf8ca725 100644
--- a/firmware/zpu/apps/txrx_uhd.c
+++ b/firmware/zpu/apps/txrx_uhd.c
@@ -46,27 +46,47 @@
//virtual registers in the firmware to store persistent values
static uint32_t fw_regs[8];
-extern uint16_t dsp0_dst_port, err0_dst_port, dsp1_dst_port;
-
static void handle_udp_data_packet(
struct socket_address src, struct socket_address dst,
unsigned char *payload, int payload_len
){
- size_t which;
- switch(dst.port){
- case USRP2_UDP_DSP0_PORT:
+ //handle ICMP destination unreachable
+ if (payload == NULL) switch(src.port){
+ case USRP2_UDP_RX_DSP0_PORT:
+ //the end continuous streaming command
+ sr_rx_ctrl0->cmd = 1 << 31; //no samples now
+ sr_rx_ctrl0->time_secs = 0;
+ sr_rx_ctrl0->time_ticks = 0; //latch the command
+ break;
+
+ case USRP2_UDP_RX_DSP1_PORT:
+ //the end continuous streaming command
+ sr_rx_ctrl1->cmd = 1 << 31; //no samples now
+ sr_rx_ctrl1->time_secs = 0;
+ sr_rx_ctrl1->time_ticks = 0; //latch the command
+ break;
+
+ case USRP2_UDP_TX_DSP0_PORT:
+ //end async update packets per second
+ sr_tx_ctrl->cyc_per_up = 0;
+ break;
+
+ default: return;
+ }
+
+ //handle an incoming UDP packet
+ size_t which = 0;
+ if (payload != 0) switch(dst.port){
+ case USRP2_UDP_RX_DSP0_PORT:
which = 0;
- dsp0_dst_port = src.port;
break;
- case USRP2_UDP_DSP1_PORT:
+ case USRP2_UDP_RX_DSP1_PORT:
which = 2;
- dsp1_dst_port = src.port;
break;
- case USRP2_UDP_ERR0_PORT:
+ case USRP2_UDP_TX_DSP0_PORT:
which = 1;
- err0_dst_port = src.port;
break;
default: return;
@@ -291,7 +311,10 @@ main(void)
#endif
printf("FPGA compatibility number: %d\n", USRP2_FPGA_COMPAT_NUM);
printf("Firmware compatibility number: %d\n", USRP2_FW_COMPAT_NUM);
-
+
+ //init readback for firmware minor version number
+ fw_regs[U2_FW_REG_VER_MINOR] = USRP2_FW_VER_MINOR;
+
#ifdef BOOTLOADER
//load the production FPGA image or firmware if appropriate
do_the_bootload_thing();
@@ -305,14 +328,14 @@ main(void)
//1) register the addresses into the network stack
register_addrs(ethernet_mac_addr(), get_ip_addr());
- pkt_ctrl_program_inspector(get_ip_addr(), USRP2_UDP_DSP0_PORT);
+ pkt_ctrl_program_inspector(get_ip_addr(), USRP2_UDP_TX_DSP0_PORT);
//2) register callbacks for udp ports we service
init_udp_listeners();
register_udp_listener(USRP2_UDP_CTRL_PORT, handle_udp_ctrl_packet);
- register_udp_listener(USRP2_UDP_DSP0_PORT, handle_udp_data_packet);
- register_udp_listener(USRP2_UDP_ERR0_PORT, handle_udp_data_packet);
- register_udp_listener(USRP2_UDP_DSP1_PORT, handle_udp_data_packet);
+ register_udp_listener(USRP2_UDP_RX_DSP0_PORT, handle_udp_data_packet);
+ register_udp_listener(USRP2_UDP_RX_DSP1_PORT, handle_udp_data_packet);
+ register_udp_listener(USRP2_UDP_TX_DSP0_PORT, handle_udp_data_packet);
#ifdef USRP2P
register_udp_listener(USRP2_UDP_UPDATE_PORT, handle_udp_fw_update_packet);
#endif
diff --git a/firmware/zpu/lib/net_common.c b/firmware/zpu/lib/net_common.c
index 2e3257b35..9a3f8c5a5 100644
--- a/firmware/zpu/lib/net_common.c
+++ b/firmware/zpu/lib/net_common.c
@@ -44,9 +44,6 @@ static const size_t out_buff_size = 2048;
static const eth_mac_addr_t BCAST_MAC_ADDR = {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff}};
#define MAX_UDP_LISTENERS 6
-//used in the top level application...
-uint16_t dsp0_dst_port, err0_dst_port, dsp1_dst_port;
-
/***********************************************************************
* 16-bit one's complement sum
**********************************************************************/
@@ -312,25 +309,13 @@ handle_icmp_packet(struct ip_addr src, struct ip_addr dst,
struct udp_hdr *udp = (struct udp_hdr *)(((char *)ip) + IP_HLEN);
if (IPH_PROTO(ip) != IP_PROTO_UDP) break;
- if (udp->dest == dsp0_dst_port){
- //the end continuous streaming command
- sr_rx_ctrl0->cmd = 1 << 31; //no samples now
- sr_rx_ctrl0->time_secs = 0;
- sr_rx_ctrl0->time_ticks = 0; //latch the command
- }
- else if (udp->dest == dsp1_dst_port){
- //the end continuous streaming command
- sr_rx_ctrl1->cmd = 1 << 31; //no samples now
- sr_rx_ctrl1->time_secs = 0;
- sr_rx_ctrl1->time_ticks = 0; //latch the command
- }
- else if (udp->dest == err0_dst_port){
- //end async update packets per second
- sr_tx_ctrl->cyc_per_up = 0;
+ struct listener_entry *lx = find_listener_by_port(udp->src);
+ if (lx){
+ struct socket_address src = make_socket_address(ip->src, udp->src);
+ struct socket_address dst = make_socket_address(ip->dest, udp->dest);
+ lx->rcvr(src, dst, NULL, 0);
}
- //struct udp_hdr *udp = (struct udp_hdr *)((char *)icmp + 28);
- //printf("icmp port unr %d\n", udp->dest);
putchar('i');
}
else {
diff --git a/fpga/usrp2/coregen/Makefile.srcs b/fpga/usrp2/coregen/Makefile.srcs
index a3a5d826d..5b2bc665a 100644
--- a/fpga/usrp2/coregen/Makefile.srcs
+++ b/fpga/usrp2/coregen/Makefile.srcs
@@ -24,4 +24,6 @@ fifo_xlnx_512x36_2clk_18to36.v \
fifo_xlnx_512x36_2clk_18to36.xco \
fifo_xlnx_512x36_2clk_prog_full.v \
fifo_xlnx_512x36_2clk_prog_full.xco \
+fifo_xlnx_1Kx18_2clk.v \
+fifo_xlnx_1Kx18_2clk.xco \
))
diff --git a/fpga/usrp2/coregen/coregen.cgp b/fpga/usrp2/coregen/coregen.cgp
index dd85a7f50..01d31bf5b 100644
--- a/fpga/usrp2/coregen/coregen.cgp
+++ b/fpga/usrp2/coregen/coregen.cgp
@@ -1,5 +1,4 @@
-# Date: Fri Oct 15 07:50:19 2010
-
+# Date: Fri Jun 10 23:12:37 2011
SET addpads = false
SET asysymbol = false
SET busformat = BusFormatAngleBracketNotRipped
@@ -19,4 +18,3 @@ SET verilogsim = true
SET vhdlsim = false
SET workingdirectory = /tmp/
-# CRC: 983b9b45
diff --git a/fpga/usrp2/coregen/fifo_generator_ug175.pdf b/fpga/usrp2/coregen/fifo_generator_ug175.pdf
index 5fba6029c..2c3e3c200 100644
--- a/fpga/usrp2/coregen/fifo_generator_ug175.pdf
+++ b/fpga/usrp2/coregen/fifo_generator_ug175.pdf
Binary files differ
diff --git a/fpga/usrp2/coregen/fifo_xlnx_1Kx18_2clk.ngc b/fpga/usrp2/coregen/fifo_xlnx_1Kx18_2clk.ngc
new file mode 100644
index 000000000..dc9519357
--- /dev/null
+++ b/fpga/usrp2/coregen/fifo_xlnx_1Kx18_2clk.ngc
@@ -0,0 +1,3 @@
+XILINX-XDB 0.1 STUB 0.1 ASCII
+XILINX-XDM V1.4e
+$4464g<,[o}e~g`n;"2*413&;$>"9 > %02?*rjx&Uhk"hffn]{hk~X9Br:4R<llj,mcj7<8<1;<=>?4193456789:;<=>?0123456789:;<=>?0123456789:;<=>?0123456789:;<=>?0127?5238;1;4<5>3:3-445<990BB][[:@FGVD:>294:?6??:HLSQQ<FLMXI044?>0d855<NFY__6}|`g^gntqX|axne26:1<12>772@D[YY4rne\ahvsqV~c~h}g_`qpawr;13:5>;5>0;KMTPR=x{elShctx]wlwct`Vdnklzj<883:4c<990BB][[:qplcZ`rdeUdk|h=;94;4238:1EC^ZT;rqkbYa}efTxe|jsi]bwvcu|531<3<:;029MKVR\3zycjQiumn\pmtb{aUeijo{e=;94;7f38;1CXZ_UU8geqgXkfex1??:1<2`>762F__\XZ5re]geqgXkfex1??:1<2`>762F__\XZ5ws]geqgXkfex1??:1<26>712@D[YY4KI@>21?699;1::7GAPTV9@LD;9<0;2<=4178LQQVR\3NDM1?::1<27>712F__\XZ5DN@?50<76880=54FNQWW>aoi48=1<3?;;0:9KPRW]]0ocxz31683:4=5<28;<=<42932?7<NFY__6IG_A=394;763;0BB][[:EKSF97=87;97?4@UURVP?BHXH6:6=0>2:09KPRW]]0OC]L31;2=0>5799n0?~<?01dd000*=81?86;;543821=18J:97;<=;7;7?3?>>=1=5L?=;7A7?3EDK;1=I?58F594BC@631804=:481236>>5923?74>?939:21=>>?3?7L<NA59BE7G?3HNO^L2?>99B@ATF48437LJKR@>1:==FLMXJ0>07;@FGVD:3611JHI\N<4<;?DBCZH6=255NDEPB828?3HNO^L27>`9B@ATF400;255NDEPB8<8?3HNO^O2?>99B@ATE48437LJKRC>1:==FLMXI0>07;@FGVG:3611JHI\M<4<;?DBCZK6=255NDEPA828?3HNO^O27>`9B@ATE400;255NDEPA8<8>3HYRBNQ]EF68FDGF;2H^>55MUR]JJCI63J>0OL6N2:AF57=D@LI@SAGLEOQF[Q_WM;1HE95LLJC7?FJLJ:1H@_74CNONMQRBL8>0OB\J_FGMAWGSAFDTECH@7:AQADRBL81O86J:8108@L0<L@K7<394DHC?55803MCJ0<?17:FJE9756>1OEL2>3?58@LG;9=427IGN<0794;1<L@K7=809;EKB84813MCJ0?09;EKB86813MCJ0909;EKB80813MCJ0;09;EKB82813MCJ0509;EKB8<813MCI0=08;EKA8469?2NBN1?>>69GMG:6:7=0HDL312<4?AOE48>556JFB=36>5803MCI0<;16:FJF979>2NBN1<16:FJF959>2NBN1:16:FJF939>2NBN1816:FJF919>2NBN1616:FJF9?9?2NB\L2?>89GMUG;93:5;6JFP@>2:2=CAYH7<374DHRA84<76>1OE]L31?48@JG;87=0HBO311<4?AIF48;5;6J@A=31:2=CGH6:?394DNC?518>3MEJ0<;50?58@JG;9<4=7IAN<0<5?AIF4;4=7IAN<2<5?AIF4=4=7IAN<4<5?AIF4?4=7IAN<6<5?AIF414=7IAN<8<5?AIE494<7IAM<02=3>BHJ5;:2:5KOC>26;1<LFH7=>08;EMA842912NDN1?::1<4?AIE48?5:6J@B=3=2>BHJ585:6J@B=1=2>BHJ5>5:6J@B=7=2>BHJ5<5:6J@B=5=2>BHJ525:6J@B=;=3>BHXH6;245KOQC?5?69?2ND\L2>>69GKUD;8730HB^M<083:2=CGYH7=3?4E59FE1633LKH<>5JN@18AKD53O297KJ<;GF@0>@CKL>0JIM_3:DGT1=ALYO?7KH8F49Eeiub92M87J@K1:K1?L653@;97D<=;H1;?LHN\YU;<55FNHVS[57?3@DBX]Q?299JJLRWW9937D@FTQ]30==NF@^[S=;7;HLJPUY7>11BBDZ__15:?LHN\Z^JXH94IOKW[5603@DBXR>>7:KMMQY7:>1BBDZP0258MKOSW9><7D@FT^263>OIA]U;::5FNHV\421<AGC_S=68;HLJPZ6>?2CEEYQ?A69JJLRX8K=0ECG[_1A4?LHN\V:O;6GAIU]3A2=NF@^T<K94IOKW[4603@DBXR?>7:KMMQY6:>1BBDZP1258MKOSW8><7D@FT^363>OIA]U:::5FNHV\521<AGC_S<68;HLJPZ7>?2CEEYQ>A69JJLRX9K=0ECG[_0A4?LHN\V;O;6GAIU]2A2=NF@^T=K94IOKW[7603@DBXR<>7:KMMQY5:>1BBDZP2258MKOSW;><7D@FT^063>OIA]U9::5FNHV\621<AGC_S?68;HLJPZ4>?2CEEYQ=A69JJLRX:K=0ECG[_3A4?LHN\V8O;6GAIU]1A2=NF@^T>K94IOKW[6603@DBXR=>7:KMMQY4:>1BBDZP3258MKOSW:><7D@FT^163>OIA]U8::5FNHV\721<AGC_S>68;HLJPZ5>?2CEEYQ<A69JJLRX;K=0ECG[_2A4?LHN\V9O;6GAIU]0A2=NF@^T?K84IOKW[D0<AGC_SO=4IOT0?LIE:2FB>6B@6:NLEACC?2FDKDMNL59OQQ733E__>;5CUU0\@1=K]]9=7A[[3^F5?ISS;VF?7A[[479OQQ2XL?1GYY:PL49NWBII=2G^TNWl;LcikwPbzzcdbn5BiomqR`ttafd97C?<;O330>H68<>0B<>94:L2422<F8:386@>0818J4733G;:<95A1037?K76:=1E=<=;;O3201=I98??7C?>659M54133G;:495A10;0?K75<2D:>=:4N0020>H6:;>0B<<<4:L2612<F882?6@>359M56633G;8=95A1207?K74;=1E=>:;;O3011=I9:<?7C?<759M56>33G;85>5A1568J425<2D:8>:4N0670>H6<<>0B<:94:L2022<F8>386@>4818J4333G;><95A1437?K72::1E=;=4N050?K7?;2D:5?5A229M655<F;;87C<=3:L176=I:<90B?9<;O137>H49:1E?>=4N277?K529:1E?;=4N250?K5?<2D84<=4N2;1?K243G>;?6@;139M27=I?;1E4>5A8518J=343G2<?6@7939M=6=I19l0BOQMURRJJZVUGYY<7CK[WNPH0>HHFL;0C?5@K09S0>VFZ]k0\D@PBTQJ@]d<X@DTNX]AALG0?UTB92[n7_OBB04\W4>X[82:7^?<;RKN[FIKD@YBCCQLHDAH2>UH][IN;6]]V@N\E2=TZ_KGSO:4SRPB0>UTZK>0XT^J339V4*aun'xm#jmw.bnh|*Kg{UyhR~ats]dgZ~hz9:;<R\jstnw564<]9%l~k }f.e`|+ekcq%Ftb|Pre]sjqtXojUsc>?00]Qavsk|8997X> gsd-vc)`kq$h`fv Mymq[wbXxg~ySjmPxnp3454XZly~`y?<2:W3+bta&{l$knv!cmi{+H~hzVxoS}`{r^e`[}iu89:8S_k|umv277=R8&myj#|i/fa{*fjlp&GscQ}d^rmpwY`kVrd~=>?4^Pfwpjs9:80Y=!hrg,qb*adp'iggu!Bxnp\vaYwf}xTknQwos2340YUmzgx<==;T2,cw`)zo%lou lljz,I}iuW{nT|cz}_fa\|jt789<T^h}zlu306>S7'nxm"h gbz-gim'Drd~R|k_qlwvZadWqey<=>8_Sgpqir6;;1^<"i}f/pe+be&jf`t"Cwos]q`Zvi|{UloRv`r123<ZTb{|f=><4U1-dvc(un&mht#mcky-N|jtX{U{by|Pgb]{kw6789UYi~{ct011?P6(o{l%~k!hcy,`hn~(EqeySz|Ppovq[beXpfx;<=?PRdqvhq74:2_;#j|i.sd,cf~)keas#@v`r^uq[uhszVmhSua}0121[Wct}e~:??5Z0.eqb+ta'nis"nbdx.O{kwYpzVzexQhc^zlv567;VXnxb{1208Q5)`zo$yj"ilx/aoo})JpfxT{Qnup\cfYg{:;<9Q]erwop4553\:$kh!rg-dg}(ddbr$Aua}_vp\tkruWniTtb|?017\V`urd};8>6[?/fpe*w`(ojr%oaew/LzlvZquWyd~Ril_ymq4561W[oxyaz>339V4*aun'xm#jmw.bnh|*Kg{U|~R~ats]dgZ~hz9:;;R\jstnw564<]9%l~k }f.e`|+ekcq%Ftb|Pws]sjqtXojUsc>?09]Qavsk|88:7X> gsd-vc)`kq$h`fv re]sjqtXj`d7<3<>;T2,cw`)zo%lou lljz,vaYwf}xTnd`31?02?P6(o{l%~k!hcy,`hn~(zmU{by|Pbhl?6;463\:$kh!rg-dg}(ddbr$~iQnup\flh;;78:7X> gsd-vc)`kq$h`fv re]sjqtXj`d783<>;T2,cw`)zo%lou lljz,vaYwf}xTnd`35?02?P6(o{l%~k!hcy,`hn~(zmU{by|Pbhl?2;463\:$kh!rg-dg}(ddbr$~iQnup\flh;?78:7X> gsd-vc)`kq$h`fv re]sjqtXj`d743<>;T2,cw`)zo%lou lljz,vaYwf}xTnd`39?03?P6(o{l%~k!hcy,`hn~(zmU{by|Pbhl\476<]9%l~k }f.e`|+ekcq%yhR~ats]amkY6:91^<"i}f/pe+be&jf`t"|k_qlwvZdnfV89<6[?/fpe*w`(ojr%oaew/sf\tkruWkceS><?;T2,cw`)zo%lou lljz,vaYwf}xTnd`P4328Q5)`zo$yj"ilx/aoo})ulVzexQmio]665=R8&myj#|i/fa{*fjlp&xoS}`{r^`jjZ0582_;#j|i.sd,cf~)keas#jPpovq[goiW>8;7X> gsd-vc)`kq$h`fv re]sjqtXj`dT4?>4U1-dvc(un&mht#mcky-q`Zvi|{UiecQ6279V4*aun'xm#jmw.bnh|*tcWyd~Rlfn^zlv5678;=0Y=!hrg,qb*adp'iggu!}d^rmpwYeagUsc>?01312>S7'nxm"h gbz-gim'{nT|cz}_ckm[}iu89::>:5Z0.eqb+ta'nis"nbdx.pg[uhszVhbbRv`r12354413\:$kh!rg-dg}(ddbr$~iQnup\flhXpfx;<=<=7:W3+bta&{l$knv!cmi{+wbXxg~ySoga_ymq45659;<0Y=!hrg,qb*adp'iggu!}d^rmpwYeagUsc>?0204?P6(o{l%~k!hcy,`hn~(zmU{by|Pbhl\|jt78999>;5Z0.eqb+ta'nis"nbdx.pg[uhszVhbbRv`r123071<]9%l~k }f.e`|+ekcq%yhR~ats]amkYg{:;<9?=6:W3+bta&{l$knv!cmi{+wbXxg~ySoga_ymq4562:>1^<"i}f/pe+be&jf`t"|k_qlwvZdnfVrd~=>?5005?P6(o{l%~k!hcy,`hn~(zmU{by|Pbhl\|jt789<946[?/fpe*w`(ojr%oaew/sf\tkruWkceSua}012554403\:$kh!rg-dg}(ddbr$~iQnup\flhXpfx;<=8=2c9V4*aun'xm#jmw.bnh|*tcWyd~Rlfn^zlv567>Vhoh=<9;T2,cw`)zo%lou lljz,vaYwf}xTnd`Pxnp34515?2_;#j|i.sd,cf~)keas#jPpovq[goiWqey<=>81348Q5)`zo$yj"ilx/aoo})ulVzexQmio]{kw67818<7X> gsd-vc)`kq$h`fv re]sjqtXj`dTtb|?01:265=R8&myj#|i/fa{*fjlp&xoS}`{r^e`858582_;#j|i.sd,cf~)keas#jPpovq[be;978;7X> gsd-vc)`kq$h`fv re]sjqtXoj692?>4U1-dvc(un&mht#mcky-q`Zvi|{Ulo1=1219V4*aun'xm#jmw.bnh|*tcWyd~Ril<5<14>S7'nxm"h gbz-gim'{nT|cz}_fa?1;473\:$kh!rg-dg}(ddbr$~iQnup\cf:16;:0Y=!hrg,qb*adp'iggu!}d^rmpwY`k5=5>=5Z0.eqb+ta'nis"nbdx.pg[uhszVmh050=0:W3+bta&{l$knv!cmi{+wbXxg~ySjm39?3e?P6(o{l%~k!hcy,`hn~(zmU{by|Pgb]35c=R8&myj#|i/fa{*fjlp&xoS}`{r^e`[47a3\:$kh!rg-dg}(ddbr$~iQnup\cfY59o1^<"i}f/pe+be&jf`t"|k_qlwvZadW:;m7X> gsd-vc)`kq$h`fv re]sjqtXojU?=k5Z0.eqb+ta'nis"nbdx.pg[uhszVmhS8?i;T2,cw`)zo%lou lljz,vaYwf}xTknQ91g9V4*aun'xm#jmw.bnh|*tcWyd~Ril_63e?P6(o{l%~k!hcy,`hn~(zmU{by|Pgb];5c=R8&myj#|i/fa{*fjlp&xoS}`{r^e`[<413\:$kh!rg-dg}(ddbr$~iQnup\cfYf{{ol0=0=6:W3+bta&{l$knv!cmi{+wbXxg~ySjmParpfc979:?1^<"i}f/pe+be&jf`t"|k_qlwvZadWhyyij2=>348Q5)`zo$yj"ilx/aoo})ulVzexQhc^cpv`a;;78=7X> gsd-vc)`kq$h`fv re]sjqtXojUjkh<5<12>S7'nxm"h gbz-gim'{nT|cz}_fa\evtbo5?5>;5Z0.eqb+ta'nis"nbdx.pg[uhszVmhSl}}ef>5:70<]9%l~k }f.e`|+ekcq%yhR~ats]dgZgtzlm7;3<9;T2,cw`)zo%lou lljz,vaYwf}xTknQnssgd8=85>2_;#j|i.sd,cf~)keas#jPpovq[beXizxnk171249V4*aun'xm#jmw.bnh|*tcWyd~Ril_`qqabY7:<1^<"i}f/pe+be&jf`t"|k_qlwvZadWhyyijQ>249V4*aun'xm#jmw.bnh|*tcWyd~Ril_`qqabY5:<1^<"i}f/pe+be&jf`t"|k_qlwvZadWhyyijQ<249V4*aun'xm#jmw.bnh|*tcWyd~Ril_`qqabY3:<1^<"i}f/pe+be&jf`t"|k_qlwvZadWhyyijQ:249V4*aun'xm#jmw.bnh|*tcWyd~Ril_`qqabY1:<1^<"i}f/pe+be&jf`t"|k_qlwvZadWhyyijQ8249V4*aun'xm#jmw.bnh|*tcWyd~Ril_`qqabY?:<1^<"i}f/pe+be&jf`t"|k_qlwvZadWhyyijQ6289V4*aun'xm#jmw.bnh|*tcWyd~Ril_`qqabYc95:5>45Z0.eqb+ta'nis"nbdx.pg[uhszVmhSl}}ef]g5979:01^<"i}f/pe+be&jf`t"|k_qlwvZadWhyyijQk1=0=6<=R8&myj#|i/fa{*fjlp&xoS}`{r^e`[duumnUo=1=1289V4*aun'xm#jmw.bnh|*tcWyd~Ril_`qqabYc95>5>45Z0.eqb+ta'nis"nbdx.pg[uhszVmhSl}}ef]g5939:01^<"i}f/pe+be&jf`t"|k_qlwvZadWhyyijQk1=4=6<=R8&myj#|i/fa{*fjlp&xoS}`{r^e`[duumnUo=191289V4*aun'xm#jmw.bnh|*tcWyd~Ril_`qqabYc9525>45Z0.eqb+ta'nis"nbdx.pg[uhszVmhSl}}ef]g59?9:11^<"i}f/pe+be&jf`t"|k_qlwvZadWhyyijQk1^21<>S7'nxm"h gbz-gim'{nT|cz}_fa\evtboVn:S<<7;T2,cw`)zo%lou lljz,vaYwf}xTknQnssgd[a7X:;20Y=!hrg,qb*adp'iggu!}d^rmpwY`kVkx~hiPd0]06==R8&myj#|i/fa{*fjlp&xoS}`{r^e`[duumnUo=R:=8:W3+bta&{l$knv!cmi{+wbXxg~ySjmParpfcZb6W<837X> gsd-vc)`kq$h`fv re]sjqtXojUjkh_e3\27><]9%l~k }f.e`|+ekcq%yhR~ats]dgZgtzlmTh<Q8299V4*aun'xm#jmw.bnh|*tcWyd~Ril_`qqabYc9V2946[?/fpe*w`(ojr%oaew/sf\tkruWniTm~|jg^f2[<423\:$kh!rg-dg}(ddbr$~iQnup\cfYg{:;<=<:;T2,cw`)zo%lou lljz,vaYwf}xTknQwos2344423\:$kh!rg-dg}(ddbr$~iQnup\cfYg{:;<?<:;T2,cw`)zo%lou lljz,vaYwf}xTknQwos2346423\:$kh!rg-dg}(ddbr$~iQnup\cfYg{:;<9<:;T2,cw`)zo%lou lljz,vaYwf}xTknQwos2340423\:$kh!rg-dg}(ddbr$~iQnup\cfYg{:;<;<:;T2,cw`)zo%lou lljz,vaYwf}xTknQwos2342423\:$kh!rg-dg}(ddbr$~iQnup\cfYg{:;<5<>;T2,cw`)zo%lou lljz,swYwf}xTnd`30?02?P6(o{l%~k!hcy,`hn~({U{by|Pbhl?5;463\:$kh!rg-dg}(ddbr${Qnup\flh;:78:7X> gsd-vc)`kq$h`fv ws]sjqtXj`d7?3<>;T2,cw`)zo%lou lljz,swYwf}xTnd`34?02?P6(o{l%~k!hcy,`hn~({U{by|Pbhl?1;463\:$kh!rg-dg}(ddbr${Qnup\flh;>78:7X> gsd-vc)`kq$h`fv ws]sjqtXj`d7;3<>;T2,cw`)zo%lou lljz,swYwf}xTnd`38?02?P6(o{l%~k!hcy,`hn~({U{by|Pbhl?=;473\:$kh!rg-dg}(ddbr${Qnup\flhX8;:0Y=!hrg,qb*adp'iggu!xr^rmpwYeagU:>=5Z0.eqb+ta'nis"nbdx.uq[uhszVhbbR<=0:W3+bta&{l$knv!cmi{+rtXxg~ySoga_203?P6(o{l%~k!hcy,`hn~({U{by|Pbhl\076<]9%l~k }f.e`|+ekcq%|~R~ats]amkY2:91^<"i}f/pe+be&jf`t"y}_qlwvZdnfV<9<6[?/fpe*w`(ojr%oaew/vp\tkruWkceS:<?;T2,cw`)zo%lou lljz,swYwf}xTnd`P8328Q5)`zo$yj"ilx/aoo})pzVzexQmio]:63=R8&myj#|i/fa{*fjlp&}yS}`{r^`jjZ~hz9:;<?94U1-dvc(un&mht#mcky-tvZvi|{UiecQwos234575>2_;#j|i.sd,cf~)keas#z|Ppovq[goiWqey<=>>269V4*aun'xm#jmw.bnh|*quWyd~Rlfn^zlv567988=7X> gsd-vc)`kq$h`fv ws]sjqtXj`dTtb|?01013>S7'nxm"h gbz-gim'~xT|cz}_ckm[}iu89:9=?84U1-dvc(un&mht#mcky-tvZvi|{UiecQwos2346403\:$kh!rg-dg}(ddbr${Qnup\flhXpfx;<===279V4*aun'xm#jmw.bnh|*quWyd~Rlfn^zlv567<;=0Y=!hrg,qb*adp'iggu!xr^rmpwYeagUsc>?05312>S7'nxm"h gbz-gim'~xT|cz}_ckm[}iu89:>>:5Z0.eqb+ta'nis"nbdx.uq[uhszVhbbRv`r12314413\:$kh!rg-dg}(ddbr${Qnup\flhXpfx;<=8=8:W3+bta&{l$knv!cmi{+rtXxg~ySoga_ymq4561988<7X> gsd-vc)`kq$h`fv ws]sjqtXj`dTtb|?01416g=R8&myj#|i/fa{*fjlp&}yS}`{r^`jjZ~hz9:;:Rlkd105?P6(o{l%~k!hcy,`hn~({U{by|Pbhl\|jt789=9;6[?/fpe*w`(ojr%oaew/vp\tkruWkceSua}0124570<]9%l~k }f.e`|+ekcq%|~R~ats]amkYg{:;<5<8;T2,cw`)zo%lou lljz,swYwf}xTnd`Pxnp345>6:91^<"i}f/pe+be&jf`t"y}_qlwvZad4949<6[?/fpe*w`(ojr%oaew/vp\tkruWni7=3<?;T2,cw`)zo%lou lljz,swYwf}xTkn2=>328Q5)`zo$yj"ilx/aoo})pzVzexQhc=1=65=R8&myj#|i/fa{*fjlp&}yS}`{r^e`818582_;#j|i.sd,cf~)keas#z|Ppovq[be;=78;7X> gsd-vc)`kq$h`fv ws]sjqtXoj6=2?>4U1-dvc(un&mht#mcky-tvZvi|{Ulo191219V4*aun'xm#jmw.bnh|*quWyd~Ril<9<14>S7'nxm"h gbz-gim'~xT|cz}_fa?=;7a3\:$kh!rg-dg}(ddbr${Qnup\cfY79o1^<"i}f/pe+be&jf`t"y}_qlwvZadW8;m7X> gsd-vc)`kq$h`fv ws]sjqtXojU9=k5Z0.eqb+ta'nis"nbdx.uq[uhszVmhS>?i;T2,cw`)zo%lou lljz,swYwf}xTknQ;1g9V4*aun'xm#jmw.bnh|*quWyd~Ril_43e?P6(o{l%~k!hcy,`hn~({U{by|Pgb]55c=R8&myj#|i/fa{*fjlp&}yS}`{r^e`[27a3\:$kh!rg-dg}(ddbr${Qnup\cfY?9o1^<"i}f/pe+be&jf`t"y}_qlwvZadW08=7X> gsd-vc)`kq$h`fv ws]sjqtXojUjkh<1<12>S7'nxm"h gbz-gim'~xT|cz}_fa\evtbo5;5>;5Z0.eqb+ta'nis"nbdx.uq[uhszVmhSl}}ef>1:70<]9%l~k }f.e`|+ekcq%|~R~ats]dgZgtzlm7?3<9;T2,cw`)zo%lou lljz,swYwf}xTknQnssgd8185>2_;#j|i.sd,cf~)keas#z|Ppovq[beXizxnk1;1279V4*aun'xm#jmw.bnh|*quWyd~Ril_`qqab:16;<0Y=!hrg,qb*adp'iggu!xr^rmpwY`kVkx~hi37?05?P6(o{l%~k!hcy,`hn~({U{by|Pgb]bwwc`4149:6[?/fpe*w`(ojr%oaew/vp\tkruWniTm~|jg=;=60=R8&myj#|i/fa{*fjlp&}yS}`{r^e`[duumnU;>85Z0.eqb+ta'nis"nbdx.uq[uhszVmhSl}}ef]260=R8&myj#|i/fa{*fjlp&}yS}`{r^e`[duumnU9>85Z0.eqb+ta'nis"nbdx.uq[uhszVmhSl}}ef]060=R8&myj#|i/fa{*fjlp&}yS}`{r^e`[duumnU?>85Z0.eqb+ta'nis"nbdx.uq[uhszVmhSl}}ef]660=R8&myj#|i/fa{*fjlp&}yS}`{r^e`[duumnU=>85Z0.eqb+ta'nis"nbdx.uq[uhszVmhSl}}ef]460=R8&myj#|i/fa{*fjlp&}yS}`{r^e`[duumnU3>85Z0.eqb+ta'nis"nbdx.uq[uhszVmhSl}}ef]:6<=R8&myj#|i/fa{*fjlp&}yS}`{r^e`[duumnUo=1>1289V4*aun'xm#jmw.bnh|*quWyd~Ril_`qqabYc95;5>45Z0.eqb+ta'nis"nbdx.uq[uhszVmhSl}}ef]g5949:01^<"i}f/pe+be&jf`t"y}_qlwvZadWhyyijQk1=1=6<=R8&myj#|i/fa{*fjlp&}yS}`{r^e`[duumnUo=1:1289V4*aun'xm#jmw.bnh|*quWyd~Ril_`qqabYc95?5>45Z0.eqb+ta'nis"nbdx.uq[uhszVmhSl}}ef]g5909:01^<"i}f/pe+be&jf`t"y}_qlwvZadWhyyijQk1=5=6<=R8&myj#|i/fa{*fjlp&}yS}`{r^e`[duumnUo=161289V4*aun'xm#jmw.bnh|*quWyd~Ril_`qqabYc9535>55Z0.eqb+ta'nis"nbdx.uq[uhszVmhSl}}ef]g5Z6502_;#j|i.sd,cf~)keas#z|Ppovq[beXizxnkRj>_00;?P6(o{l%~k!hcy,`hn~({U{by|Pgb]bwwc`Wm;T>?64U1-dvc(un&mht#mcky-tvZvi|{UloRo|rde\`4Y4:11^<"i}f/pe+be&jf`t"y}_qlwvZadWhyyijQk1^61<>S7'nxm"h gbz-gim'~xT|cz}_fa\evtboVn:S8<7;T2,cw`)zo%lou lljz,swYwf}xTknQnssgd[a7X>;20Y=!hrg,qb*adp'iggu!xr^rmpwY`kVkx~hiPd0]46==R8&myj#|i/fa{*fjlp&}yS}`{r^e`[duumnUo=R6=8:W3+bta&{l$knv!cmi{+rtXxg~ySjmParpfcZb6W08>7X> gsd-vc)`kq$h`fv ws]sjqtXojUsc>?0106?P6(o{l%~k!hcy,`hn~({U{by|Pgb]{kw67888>7X> gsd-vc)`kq$h`fv ws]sjqtXojUsc>?0306?P6(o{l%~k!hcy,`hn~({U{by|Pgb]{kw678:8>7X> gsd-vc)`kq$h`fv ws]sjqtXojUsc>?0506?P6(o{l%~k!hcy,`hn~({U{by|Pgb]{kw678<8>7X> gsd-vc)`kq$h`fv ws]sjqtXojUsc>?0706?P6(o{l%~k!hcy,`hn~({U{by|Pgb]{kw678>8>7X> gsd-vc)`kq$h`fv ws]sjqtXojUsc>?091;?P6(o{l%~k!hl1,q`*au9'myhn<!rea,IdbcW{nThnQf_`fgwpd789::<>64U1-dvc(un&mg<#|k/fp2*btck;$yhn!Baef\vaYckVcTmij|uc234575;11^<"i}f/pe+bj7&{n$k?!gsf`6+tck&GjhiQ}d^f`[lYflmy~n=>?0060<>S7'nxm"h gm2-va)`z8$l~im=.sf`+HgclVxoSimPi^cg`vse89:;=;=8;T2,cw`)zo%l`= }d.eq5+aulj8%~im M`fg[wbXljUbSljkst`34565;>1^<"i}f/pe+bj7&{n$k?!gsf`6+tck&GjhiQ}d^f`[lYflmy~n=>?0514?P6(o{l%~k!hl1,q`*au9'myhn<!rea,IdbcW{nThnQf_`fgwpd789:=?:5Z0.eqb+ta'nf;"j gs3-cwbd:'xoo"Cnde]q`ZbdW`Ujhi}zb1234=5d3\:$kh!rg-dh5(ul&my=#i}db0-vae(EhnoSjPdb]j[dbc{|h;<=>Pcx>2:6><]9%l~k }f.eo4+tc'nx:"j|kc3,q`f)J{|hThdhi_vp\vaYseyUhu1>1399V4*aun'xm#jb?.sf,cw7)o{nh>#|kc.OpqgYcaolT{Q}d^vntZe~484846[?/fpe*w`(oe:%~i!hr0,dvae5&{nh#@}zb^fjbcYpzVxoSyc_b{?6;5?3\:$kh!rg-dh5(ul&my=#i}db0-vae(EziSigif^uq[wbX|dzTot2<>2:8Q5)`zo$yj"ic0/pg+bt6&nxoo? }db-NwpdXl`lmSz|Pre]wiuYdq5>5?55Z0.eqb+ta'nf;"j gs3-cwbd:'xoo"C|uc]gmc`X{UyhRzbp^az808402_;#j|i.sd,ci6)zm%l~< hrea1*wbd'Dy~nRjffg]tvZtcW}g{Snw36?1;?P6(o{l%~k!hl1,q`*au9'myhn<!rea,IvseWmcmjRy}_sf\phvXkp6<2>64U1-dvc(un&mg<#|k/fp2*btck;$yhn!Bst`\`l`aW~xT~iQ{mq]`}9>9;01^<"i}f/pe+bj7&{n$k?!gsf`6+tck&GxyoQkigd\swYulV~f|Rbzt=2=7<=R8&myj#|i/fn3*wb(o{;%kjl2/pgg*Kt}kUoekhPws]q`ZrjxVf~x1?1389V4*aun'xm#jb?.sf,cw7)o{nh>#|kc.OpqgYcaolT{Q}d^vntZjr|585?45Z0.eqb+ta'nf;"j gs3-cwbd:'xoo"C|uc]gmc`X{UyhRzbp^nvp959;01^<"i}f/pe+bj7&{n$k?!gsf`6+tck&GxyoQkigd\swYulV~f|Rbzt=6=7<=R8&myj#|i/fn3*wb(o{;%kjl2/pgg*Kt}kUoekhPws]q`ZrjxVf~x1;1389V4*aun'xm#jb?.sf,cw7)o{nh>#|kc.OpqgYcaolT{Q}d^vntZjr|5<5?45Z0.eqb+ta'nf;"j gs3-cwbd:'xoo"C|uc]gmc`X{UyhRzbp^nvp919;01^<"i}f/pe+bj7&{n$k?!gsf`6+tck&GxyoQkigd\swYulV~f|Rbzt=:=7<=R8&myj#|i/fn3*wb(o{;%kjl2/pgg*Kt}kUoekhPws]q`ZrjxVf~x171389V4*aun'xm#jb?.sf,cw7)o{nh>#|kc.OpqgYcaolT{Q}d^vntZ~hz5:5?45Z0.eqb+ta'nf;"j gs3-cwbd:'xoo"C|uc]gmc`X{UyhRzbp^zlv979;01^<"i}f/pe+bj7&{n$k?!gsf`6+tck&GxyoQkigd\swYulV~f|Rv`r=0=7<=R8&myj#|i/fn3*wb(o{;%kjl2/pgg*Kt}kUoekhPws]q`ZrjxVrd~1=1389V4*aun'xm#jb?.sf,cw7)o{nh>#|kc.OpqgYcaolT{Q}d^vntZ~hz5>5?45Z0.eqb+ta'nf;"j gs3-cwbd:'xoo"C|uc]gmc`X{UyhRzbp^zlv939;01^<"i}f/pe+bj7&{n$k?!gsf`6+tck&GxyoQkigd\swYulV~f|Rv`r=4=7<=R8&myj#|i/fn3*wb(o{;%kjl2/pgg*Kt}kUoekhPws]q`ZrjxVrd~191389V4*aun'xm#jb?.sf,cw7)o{nh>#|kc.OpqgYcaolT{Q}d^vntZ~hz525?45Z0.eqb+ta'nf;"j gs3-cwbd:'xoo"C|uc]gmc`X{UyhRzbp^zlv9?9;91^<"i}f/pe+bj7&{n$k?!gsf`6+tck&nbjkQxr^pg[qkw494946[?/fpe*w`(oe:%~i!hr0,dvae5&{nh#jPdb]j[54?3\:$kh!rg-dh5(ul&my=#i}db0-vae(zmUooRgP13;8Q5)`zo$yj"ic0/pg+bt6&nxoo? }db-q`ZbdW`U:<?64U1-dvc(un&mg<#|k/fp2*btck;$yhn!}d^f`[lY5:11^<"i}f/pe+bj7&{n$k?!gsf`6+tck&xoSimPi^11<>S7'nxm"h gm2-va)`z8$l~im=.sf`+wbXljUbS9<7;T2,cw`)zo%l`= }d.eq5+aulj8%~im re]ggZoX=;20Y=!hrg,qb*ak8'xo#j|>.fpgg7(ulj%yhRjl_h]56==R8&myj#|i/fn3*wb(o{;%kjl2/pgg*tcWmiTeR9=8:W3+bta&{l$ka>!re-dv4(`zmi9"jl/sf\`fYnW1837X> gsd-vc)`d9$yh"i}1/eq`f4)zmi$~iQkc^k\=67<]9%l~k }f.eo4+tc'nx:"j|kc3,q`f)ulVnhSdQbuy2347:76:80Y=!hrg,qb*ak8'xo#j|>.fpgg7(ulj%yhRjl_h]nq}678;6;2<==;T2,cw`)zo%l`= }d.eq5+aulj8%~im re]ggZoXe|r;<=<311<07>S7'nxm"h gm2-va)`z8$l~im=.sf`+wbXljUbS`{w012184699:;0Y=!hrg,qb*ak8'xo#j|>.fpgg7(ulj%yhRjl_h]nq}678;6:2><4U1-dvc(un&mg<#|k/fp2*btck;$yhn!}d^f`[lYj}q:;<?2>>012?P6(o{l%~k!hl1,q`*au9'myhn<!rea,vaYckVcTaxv?010?6;553\:$kh!rg-dh5(ul&my=#i}db0-vae(zmUooRgPmtz3454;:7;8=6[?/fpe*w`(oe:%~i!hr0,dvae5&{nh#jPdb]j[hs89:90>0<2:W3+bta&{l$ka>!re-dv4(`zmi9"jl/sf\`fYnWds<=>=<2<274=R8&myj#|i/fn3*wb(o{;%kjl2/pgg*tcWmiTeRczx1236929;;1^<"i}f/pe+bj7&{n$k?!gsf`6+tck&xoSimPi^ov|567:5>5=>:4U1-dvc(un&mg<#|k/fp2*btck;$yhn!}d^f`[lYj}q:;<?2;>0327==R8&myj#|i/fn3*wb(o{;%kjl2/pgg*tcWmiTeRczx123692998;T_Z><1:W3+bta&{l$ka>!re-dv4(`zmi9"jl/sf\`fYnWds<=>=<4<07>S7'nxm"h gm2-va)`z8$l~im=.sf`+wbXljUbS`{w012180869:80Y=!hrg,qb*ak8'xo#j|>.fpgg7(ulj%yhRjl_h]nq}678;6>2?=>;T2,cw`)zo%l`= }d.eq5+aulj8%~im re]ggZoXe|r;<=<36?16?P6(o{l%~k!hl1,q`*au9'myhn<!rea,vaYckVcTaxv?010?2;YT_99:7X> gsd-vc)`d9$yh"i}1/eq`f4)zmi$~iQkc^k\ip~78987;3=:;T2,cw`)zo%l`= }d.eq5+aulj8%~im re]ggZoXe|r;<=<37?]PS5563\:$kh!rg-dh5(ul&my=#i}db0-vae(zmUooRgPmtz3454;079>7X> gsd-vc)`d9$yh"i}1/eq`f4)zmi$~iQkc^k\ip~7898743Q\W116?P6(o{l%~k!hl1,q`*au9'myhn<!rea,vaYckVcTaxv?010?<;YT_8927X> gsd-vc)`d9$yh"i}1/eq`f4)zmi$~iQkc^k\ip~7898743Q\W0]PS5563\:$kh!rg-dh5(ul&my=#i}db0-vae(zmUooRgPmtz3454;17987X> gsd-vc)`d9$yh"i}1/eq`f4)zmi$~iQkc^k\ip~7898753<>369V4*aun'xm#jb?.sf,cw7)o{nh>#|kc.pg[aeXaVg~t=>?2=;=64YT_99<7X> gsd-vc)`d9$yh"i}1/eq`f4)zmi$~iQkc^k\ip~7898753<>_RU272=R8&myj#|i/fn3*wb(o{;%kjl2/pgg*tcWmiTeRczx12369?9;9UX[==<;T2,cw`)zo%l`= }d.eq5+aulj8%~im re]ggZoXe|r;<=<39?1276=R8&myj#|i/fn3*wb(o{;%kjl2/pgg*tcWmiTeRczx12369?9;1997X> gsd-vc)`d9$yh"i}1/eq`f4)zmi$~iQkc^k\ip~7898753:<3:W3+bta&{l$ka>!re-dv4(`zmi9"jl/sf\`fYnWds<=>=<8<7561<]9%l~k }f.eo4+tc'nx:"j|kc3,q`f)ulVnhSdQbuy2347:>6=;T_Z>=a:W3+bta&{l$ka>!re-dv4(un~l#_OB_SF\AKYA_O^:>45Z0.eqb+ta'nf;"j gs3-vcqa|&XJAR\JGNWW[@H6:k1^<"i}f/pe+bj7&{n$k?!rguep*TFEV\J@DJPFVDW54543\:$kh!rg-dh5(ul&my=#|iwgv,gptuWo}mxR}{aug\BVKXNOn:?;5Z0.eqb+ta'nf;"j gs3-vcqa|&i~~Qiwgv\wqgsmVLXARHId0/Jj6><]9%l~k }f.eo4+tc'nx:"hxfu-`qwtXn~lS~zntd]EWHYANm;&Ec?>329V4*aun'xm#jb?.sf,cw7)zo}mx"mzrs]escrX{}kiRH\M^DE`7513\:$kh!rg-dh5(ul&my=#|iwgv,gptuWo}mxR}{aug\BVKXNOn9!D`<8:W3+bta&{l$ka>!re-dv4(un~l#n{}r^dtbqYt|h~nSK]B_GDg6(Oi98837X> gsd-vc)`d9$yh"i}1/pescr(mdzuRhxfu]ef71<]9%l~k }f.eo4+tc'nx:"hxfu-fiur~Wo}mxRg=e:W3+bta&{l$ka>!re-dv4(un~l#hctx]escrXaVey<=>?2g9V4*aun'xm#jb?.sf,cw7)zo}mx"kbpu{\br`sW`Ud~=>?0006?P6(o{l%~k!hl1,q`*au9'xm{kz urgq[sgkam827X> gsd-vc)`d9$yh"i}ar,qwqu(k9%hm|vndv?4;4>3\:$kh!rg-dh5(ul&mym~ }suq,g5)di{xrbhz31?0:?P6(o{l%~k!hl1,q`*auiz$yy} c1-`ewt~fl~7>3<6;T2,cw`)zo%l`= }d.eqev(u{}y$o=!laspzj`r;;78m7X> gsd-vc)`d9$yh"i}ar,qwqu(k9%laxv!glY3Y+aj9'g:>k5Z0.eqb+ta'nf;"j gscp*wus{&i;#jczx/en_4[)ody%a~<i;T2,cw`)zo%l`= }d.eqev(u{}y$o=!hmtz-ch]5U'mf#c|2g9V4*aun'xm#jb?.sf,cwgt&{y"m?/fov|+ajS:W%k`}!mr0e?P6(o{l%~k!hl1,q`*auiz$yy} c1-dip~)odQ?Q#ibs/op66=R8&myj#|i/fn3*wb(o{kx"}{s.a3+s7;87887X> gsd-vc)`d9$yh"i}ar,qwqu(k9%}=1?1229V4*aun'xm#jb?.sf,cwgt&{y"m?/w3?6;443\:$kh!rg-dh5(ul&mym~ }suq,g5)q9595>>5Z0.eqb+ta'nf;"j gscp*wus{&i;#{?34?0a?P6(o{l%~k!hl1,q`*auiz$yy} c1-u5Z6Xign;<=>>2c9V4*aun'xm#jb?.sf,cwgt&{y"m?/w3\5Zgil9:;<<<m;T2,cw`)zo%l`= }d.eqev(u{}y$o=!y1^0\ekb789::>o5Z0.eqb+ta'nf;"j gscp*wus{&i;#{?P3^cm`567888i7X> gsd-vc)`d9$yh"i}ar,qwqu(k9%}=R:Paof34566:01^<"i}f/pe+bj7&{n$ko|.sqww*e6'jky~t`jt=2=6<=R8&myj#|i/fn3*wb(o{kx"}{s.a2+fguzpdnx1?1289V4*aun'xm#jb?.sf,cwgt&{y"m>/bcqv|hb|585>45Z0.eqb+ta'nf;"j gscp*wus{&i:#no}rxlfp959:o1^<"i}f/pe+bj7&{n$ko|.sqww*e6'ng~t#ib[1_-ch7)e88m7X> gsd-vc)`d9$yh"i}ar,qwqu(k8%laxv!glY2Y+aj{'gx>k5Z0.eqb+ta'nf;"j gscp*wus{&i:#jczx/en_7[)ody%a~<i;T2,cw`)zo%l`= }d.eqev(u{}y$o<!hmtz-ch]4U'mf#c|2g9V4*aun'xm#jb?.sf,cwgt&{y"m>/fov|+ajS=W%k`}!mr00?P6(o{l%~k!hl1,q`*auiz$yy} c0-u5969::1^<"i}f/pe+bj7&{n$ko|.sqww*e6';7=3<<;T2,cw`)zo%l`= }d.eqev(u{}y$o<!y1=0=66=R8&myj#|i/fn3*wb(o{kx"}{s.a2+s7;;7887X> gsd-vc)`d9$yh"i}ar,qwqu(k8%}=1:12c9V4*aun'xm#jb?.sf,cwgt&{y"m>/w3\4Zgil9:;<<<m;T2,cw`)zo%l`= }d.eqev(u{}y$o<!y1^3\ekb789::>o5Z0.eqb+ta'nf;"j gscp*wus{&i:#{?P2^cm`567888i7X> gsd-vc)`d9$yh"i}ar,qwqu(k8%}=R=Paof34566:k1^<"i}f/pe+bj7&{n$ko|.sqww*e6';T8Road12344473\:$kh!rg-dh5(ul&mym~ }suq,gjkw8;:0Y=!hrg,qb*ak8'xo#j|ns/pppv)dgdz:>45Z0.eqb+ta'nf;"j gscp*wus{&xjaRkbpu{\bgYn;91^<"i}f/pe+bj7&{n$ko|.sqww*tfeVof|ywPfc]j[jt789:8=6[?/fpe*w`(oe:%~i!hr`q-vvrt'{kfShctx]efZoXg{:;<=?>f:W3+bta&{l$ka>!re-qehYqiecoSkyit318Q5)`zo$yj"ic0/pg+wvi|{%Fob{at^alqkr5<2_;#j|i.sd,ci6)zm%y|cz}/LalqkrXkfex<<;;T2,cw`)zo%l`= }d.psjqt(Eje~byQlotlw672<]9%l~k }f.eo4+tc'{zex!BcnwmpZeh}g~8>95Z0.eqb+ta'nf;"j rqlwv*Kdg|dSnaznu610>S7'nxm"h gm2-va)uxg~y#@m`uov\gjsi|<8?7X> gsd-vc)`d9$yh"|nup,Ifirf}Uhcx`{6368Q5)`zo$yj"ic0/pg+wvi|{%Fob{at^alqkr0:=1^<"i}f/pe+bj7&{n$~}`{r.O`kphsWje~by6=4:W3+bta&{l$ka>!re-qtkru'DidyczPcnwmp<4>3\:$kh!rg-dh5(ul&x{by| MbmvjqYdg|dSnw30?0`?P6(o{l%~k!hl1,q`*twf}x$Anaznu]`kphsWjs7<3Q}t3;8Q5)`zo$yj"ic0/pg+wvi|{%Fob{at^alqkrXkp6:2?m4U1-dvc(un&mg<#|k/srmpw)JkfexRm`uov\g|:66Vx>45Z0.eqb+ta'nf;"j rqlwv*Kdg|dSnaznu]`}949:j1^<"i}f/pe+bj7&{n$~}`{r.O`kphsWje~byQly=0=[wr512_;#j|i.sd,ci6)zm%y|cz}/LalqkrXkfexRmv<2<1g>S7'nxm"h gm2-va)uxg~y#@m`uov\gjsi|Vir0>0Pru0:?P6(o{l%~k!hl1,q`*twf}x$Anaznu]`kphsWjs783<l;T2,cw`)zo%l`= }d.psjqt(Eje~byQlotlw[f;<7Uyx?74U1-dvc(un&mg<#|k/srmpw)JkfexRm`uov\g|:26;i0Y=!hrg,qb*ak8'xo#~ats-Ngjsi|VidyczPcx>6:Zts:01^<"i}f/pe+bj7&{n$~}`{r.O`kphsWje~byQly=4=6f=R8&myj#|i/fn3*wb(zyd~"Clotlw[firf}Uhu181_sv1=>S7'nxm"h gm2-va)uxg~y#@m`uov\gjsi|Vir0:0=c:W3+bta&{l$ka>!re-qtkru'DidyczPcnwmpZe~4>4T~y<6;T2,cw`)zo%l`= }d.psjqt(Eje~byQlotlw[f;078h7X> gsd-vc)`d9$yh"|nup,Ifirf}Uhcx`{_b{?<;Yu|;k0Y=!hrg,qb*ak8'xo#~ats-Ngjsi|VidyczPxnp?4;4f3\:$kh!rg-dh5(ul&x{by| MbmvjqYdg|dSua}<0<1e>S7'nxm"h gm2-va)uxg~y#@m`uov\gjsi|Vrd~1<12`9V4*aun'xm#jb?.sf,vuhsz&Ghcx`{_bmvjqYg{682?o4U1-dvc(un&mg<#|k/srmpw)JkfexRm`uov\|jt;<78j7X> gsd-vc)`d9$yh"|nup,Ifirf}Uhcx`{_ymq8085i2_;#j|i.sd,ci6)zm%y|cz}/LalqkrXkfexRv`r=4=6d=R8&myj#|i/fn3*wb(zyd~"Clotlw[firf}Usc28>3c8Q5)`zo$yj"ic0/pg+wvi|{%Fob{at^alqkrXpfx743<n;T2,cw`)zo%l`= }d.psjqt(Eje~byQlotlw[}iu4049h6[?/fpe*w`(oe:%~i!}povq+Heh}g~Tob{at^zlv9?9W{~:j6[?/fpe*w`(oe:%~i!}povq+firf}6;2<h4U1-dvc(un&mg<#|k/srmpw)dg|d0<0>f:W3+bta&{l$ka>!re-qtkru'je~by2=>0d8Q5)`zo$yj"ic0/pg+wvi|{%hcx`{<2<2b>S7'nxm"h gm2-va)uxg~y#naznu>7:4`<]9%l~k }f.eo4+tc'{zex!lotlw8086n2_;#j|i.sd,ci6)zm%y|cz}/bmvjq:168l0Y=!hrg,qb*ak8'xo#~ats-`kphs4>4:j6[?/fpe*w`(oe:%~i!}povq+firf}632<h4U1-dvc(un&mg<#|k/srmpw)dg|d040>e:W3+bta&{l$ka>!re-qtkru'je~byQ?1d9V4*aun'xm#jb?.sf,vuhsz&idyczP10g8Q5)`zo$yj"ic0/pg+wvi|{%hcx`{_33f?P6(o{l%~k!hl1,q`*twf}x$ob{at^12a>S7'nxm"h gm2-va)uxg~y#naznu]75`=R8&myj#|i/fn3*wb(zyd~"m`uov\14c<]9%l~k }f.eo4+tc'{zex!lotlw[37b3\:$kh!rg-dh5(ul&x{by| cnwmpZ16m2_;#j|i.sd,ci6)zm%y|cz}/bmvjqY?9l1^<"i}f/pe+bj7&{n$~}`{r.alqkrX1;80Y=!hrg,qb*ak8'xo#~ats-`kphsWm;7<3<=;T2,cw`)zo%l`= }d.psjqt(kfexRj><0<16>S7'nxm"h gm2-va)uxg~y#naznu]g5949:;1^<"i}f/pe+bj7&{n$~}`{r.alqkrXl8682?<4U1-dvc(un&mg<#|k/srmpw)dg|dSi?34?01?P6(o{l%~k!hl1,q`*twf}x$ob{at^f28085:2_;#j|i.sd,ci6)zm%y|cz}/bmvjqYc95<5>?5Z0.eqb+ta'nf;"j rqlwv*eh}g~Th<28>308Q5)`zo$yj"ic0/pg+wvi|{%hcx`{_e3?<;453\:$kh!rg-dh5(ul&x{by| cnwmpZb64049=6[?/fpe*w`(oe:%~i!}povq+firf}Uo=R>=1:W3+bta&{l$ka>!re-qtkru'je~byQk1^315>S7'nxm"h gm2-va)uxg~y#naznu]g5Z4592_;#j|i.sd,ci6)zm%y|cz}/bmvjqYc9V99=6[?/fpe*w`(oe:%~i!}povq+firf}Uo=R:=1:W3+bta&{l$ka>!re-qtkru'je~byQk1^715>S7'nxm"h gm2-va)uxg~y#naznu]g5Z0592_;#j|i.sd,ci6)zm%y|cz}/bmvjqYc9V=9=6[?/fpe*w`(oe:%~i!}povq+firf}Uo=R6=1:W3+bta&{l$ka>!re-qtkru'je~byQk1^;1=>S7'nxm"h gm2-sw)`hy%{~z|/b3,gdtuqgo0=0=9:W3+bta&{l$ka>!ws-dsdu)z~x#n? c`pq}kcs484956[?/fpe*w`(oe:%{!hw`q-svrt'j;$ol|}yogw878512_;#j|i.sd,ci6){%l{l}!wrvp+f7(khxyuck{<2<1b>S7'nxm"h gm2-sw)`hy%{~z|/b3,chs&ngP<P hm0,n57`<]9%l~k }f.eo4+qu'n}j#y|tr-`5*aj}q$laV?R.fop*hu5n2_;#j|i.sd,ci6){%l{l}!wrvp+f7(ods"jcT2\,div(j{;l0Y=!hrg,qb*ak8'}y#jyns/uppv)d9&mfyu hmZ1^*bkt&dy9j6[?/fpe*w`(oe:%{!hw`q-svrt'j;$k`{w.foX0X(`ez$f?=4U1-dvc(un&mg<#y}/fubw+qt|z%h="x><1<17>S7'nxm"h gm2-sw)`hy%{~z|/b3,r4:66;90Y=!hrg,qb*ak8'}y#jyns/uppv)d9&|:0?0=3:W3+bta&{l$ka>!ws-dsdu)z~x#n? v0>0:75<]9%l~k }f.eo4+qu'n}j#y|tr-`5*p64=49n6[?/fpe*w`(oe:%{!hw`q-svrt'j;$z<Q?_`lg45679;h0Y=!hrg,qb*ak8'}y#jyns/uppv)d9&|:S<Qnne234575j2_;#j|i.sd,ci6){%l{l}!wrvp+f7(~8U9Sl`k012357d<]9%l~k }f.eo4+qu'n}j#y|tr-`5*p6W:Ujbi>?0131f>S7'nxm"h gm2-sw)`hy%{~z|/b3,r4Y3Whdo<=>?13;8Q5)`zo$yj"ic0/uq+bqf{'}xx~!l2.abvwim}6;2?74U1-dvc(un&mg<#y}/fubw+qt|z%h>"mnrs{maq:66;30Y=!hrg,qb*ak8'}y#jyns/uppv)d:&ij~waeu>1:7?<]9%l~k }f.eo4+qu'n}j#y|tr-`6*efz{seiy2<>3d8Q5)`zo$yj"ic0/uq+bqf{'}xx~!l2.enq}(`eR:V"jc>.l31b>S7'nxm"h gm2-sw)`hy%{~z|/b0,chs&ngP=P hmr,nw7`<]9%l~k }f.eo4+qu'n}j#y|tr-`6*aj}q$laV<R.fop*hu5n2_;#j|i.sd,ci6){%l{l}!wrvp+f4(ods"jcT3\,div(j{;l0Y=!hrg,qb*ak8'}y#jyns/uppv)d:&mfyu hmZ6^*bkt&dy9?6[?/fpe*w`(oe:%{!hw`q-svrt'j8$z<2?>318Q5)`zo$yj"ic0/uq+bqf{'}xx~!l2.t28485;2_;#j|i.sd,ci6){%l{l}!wrvp+f4(~8692?=4U1-dvc(un&mg<#y}/fubw+qt|z%h>"x><2<17>S7'nxm"h gm2-sw)`hy%{~z|/b0,r4:36;h0Y=!hrg,qb*ak8'}y#jyns/uppv)d:&|:S=Qnne234575j2_;#j|i.sd,ci6){%l{l}!wrvp+f4(~8U:Sl`k012357d<]9%l~k }f.eo4+qu'n}j#y|tr-`6*p6W;Ujbi>?0131f>S7'nxm"h gm2-sw)`hy%{~z|/b0,r4Y4Whdo<=>?13`8Q5)`zo$yj"ic0/uq+bqf{'}xx~!l2.t2[1Yffm:;<=?=0:W3+bta&{l$ka>!ws-dsdu)z~x#nabp003?P6(o{l%~k!hl1,tv*apiz$|y} cnos67><]9%l~k }f.eo4+qu'n}j#y|tr-qehYa}efTjoQf249V4*aun'xm#jb?.vp,crgt&~y"|nm^dvhiYn:j1^<"i}f/pe+bj7&~x$kzo|.vqww*tfeVl~`aQf_np34565l2_;#j|i.sd,ci6){%l{l}!wrvp+wgjWog`RgPos234574k2_;#j|i.sd,ci6){%l{im>.vf`a}r(EhnoSz|Pd`vb[firf}UbSljk0123555d3\:$kh!rg-dh5(pz&m|hn?!weaf|q)JimnT{Qkauc\gjsi|VcTmij?012266e<]9%l~k }f.eo4+qu'n}oo< xdbg{p*KflmU|~Rjnt`]`kphsW`Ujhi>?01377f=R8&myj#|i/fn3*rt(o~nh=#ykcdzw+HgclV}ySio{a^alqkrXaVkoh=>?0040f>S7'nxm"h gm2-sw)`mi:"zjleyv,IdbcW~xThlzn_bmvjqYnWhno<=>?22`8Q5)`zo$yj"ic0/uq+bqck8$|hnkwt.Ob`aYpzVnjxlQlotlw[lYflm:;<=:<b:W3+bta&{l$ka>!ws-dsae6&~nhiuz M`fg[rtXlh~jSnaznu]j[dbc89:;:>l4U1-dvc(un&mg<#y}/fugg4(pljosx"Cnde]tvZbf|hUhcx`{_h]b`a67892?<6[?/fpe*w`(oe:%{!hwea2*rbdmq~$Aljk_vp\`drfWje~byQf_`fg4567Wjs7=3:?;T2,cw`)zo%l`= xr.et`f7)minty!Baef\swYci}kTob{at^k\eab789:Tot26>548Q5)`zo$yj"ic0/uq+bqck8$|hnkwt.Ob`aYpzVnjxlQlotlw[lYflm:;<=Qly=;=74YT_8>97X> gsd-vc)`d9$|~"ixdb3-saebp}%FmijPws]geqgXkfexRgPaef3456Xkp6229?;5:W3+bta&{l$ka>!ws-dsae6&~nhiuz M`fg[rtXlh~jSnaznu]j[dbc89:;Snw39?]a`a2312_;#j|i.sd,ci6){%l{im>.vf`a}r(EhnoSz|Pd`vb[firf}UbSljk0123[}iu484:=RGAV^277>S7'nxm"h gm2-sw)`mi:"zjleyv,IdbcW~xThlzn_bmvjqYnWhno<=>?_ymq87869=90Y=!hrg,qb*ak8'}y#jykc0,t`fc|&GjhiQxr^fbpdYdg|dSdQnde2345Yg{682<?;3:W3+bta&{l$ka>!ws-dsae6&~nhiuz M`fg[rtXlh~jSnaznu]j[dbc89:;Sua}<5<2561<]9%l~k }f.eo4+qu'n}oo< xdbg{p*Kt}kUoekhPws]q`ZrjxVir0=0<7:W3+bta&{l$ka>!ws-dsae6&~nhiuz Mrwa[aoanV}ySjPtlr\g|:66:=0Y=!hrg,qb*ak8'}y#jykc0,t`fc|&GxyoQkigd\swYulV~f|Rmv<3<03>S7'nxm"h gm2-sw)`mi:"zjleyv,IvseWmcmjRy}_sf\phvXkp682>94U1-dvc(un&mg<#y}/fugg4(pljosx"C|uc]gmc`X{UyhRzbp^az8184?2_;#j|i.sd,ci6){%l{im>.vf`a}r(EziSigif^uq[wbX|dzTot2:>258Q5)`zo$yj"ic0/uq+bqck8$|hnkwt.OpqgYcaolT{Q}d^vntZe~4?48;6[?/fpe*w`(oe:%{!hwea2*rbdmq~$A~{m_ekebZquW{nTx`~Pcx>4:61<]9%l~k }f.eo4+qu'n}oo< xdbg{p*Kt}kUoekhPws]q`ZrjxVir050<8:W3+bta&{l$ka>!ws-dsae6&~nhiuz Mrwa[aoanV}ySjPtlr\hpr;87937X> gsd-vc)`d9$|~"ixdb3-saebp}%FxlPdhde[rtXzmUa}Qcuu>2:6><]9%l~k }f.eo4+qu'n}oo< xdbg{p*Kt}kUoekhPws]q`ZrjxVf~x1<1399V4*aun'xm#jb?.vp,crbd9'}oohv{/LqvfZbnnoU|~R|k_uos[iss4:4846[?/fpe*w`(oe:%{!hwea2*rbdmq~$A~{m_ekebZquW{nTx`~Pltv?0;5?3\:$kh!rg-dh5(pz&m|hn?!weaf|q)J{|hThdhi_vp\vaYseyUgyy2:>2:8Q5)`zo$yj"ic0/uq+bqck8$|hnkwt.OpqgYcaolT{Q}d^vntZjr|5<5?55Z0.eqb+ta'nf;"z| gvf`5+qcklr#@}zb^fjbcYpzVxoSyc_mww828402_;#j|i.sd,ci6){%l{im>.vf`a}r(EziSigif^uq[wbX|dzT`xz38?1;?P6(o{l%~k!hl1,tv*aplj;%{imjxu-NwpdXl`lmSz|Pre]wiuYk}}622>64U1-dvc(un&mg<#y}/fugg4(pljosx"C|uc]gmc`X{UyhRzbp^zlv969;11^<"i}f/pe+bj7&~x$kzjl1/ugg`~s'Dy~nRjffg]tvZtcW}g{Sua}<0<0<>S7'nxm"h gm2-sw)`mi:"zjleyv,IvseWmcmjRy}_sf\phvXpfx7>3=7;T2,cw`)zo%l`= xr.et`f7)minty!Bst`\`l`aW~xT~iQ{mq]{kw:46:20Y=!hrg,qb*ak8'}y#jykc0,t`fc|&GxyoQkigd\swYulV~f|Rv`r=6=7==R8&myj#|i/fn3*rt(o~nh=#ykcdzw+HurjVnbjkQxr^pg[qkwWqey080<8:W3+bta&{l$ka>!ws-dsae6&~nhiuz Mrwa[aoanV}ySjPtlr\|jt;>7937X> gsd-vc)`d9$|~"ixdb3-saebp}%FxlPdhde[rtXzmUa}Qwos>4:6><]9%l~k }f.eo4+qu'n}oo< xdbg{p*Kt}kUoekhPws]q`ZrjxVrd~161399V4*aun'xm#jb?.vp,crbd9'}oohv{/LqvfZbnnoU|~R|k_uos[}iu4049j6[?/fpe*w`(oe:%{!hwea2*rbdmq~$hdhi_vp\vaYsey6;2?h4U1-dvc(un&mg<#y}/fugg4(pljosx"y}_ecweZeh}g~TeR>=f:W3+bta&{l$ka>!ws-dsae6&~nhiuz ws]geqgXkfexRgP1228Q5)`zo$yj"ic0/uq+bqck8$|hnkwt.uq[agsiVidyczPi^336c=R8&myj#|i/fn3*rt(o~nh=#ykcdzw+rtXlh~jSnaznu]j[74a3\:$kh!rg-dh5(pz&m|hn?!weaf|q)pzVnjxlQlotlw[lY4:o1^<"i}f/pe+bj7&~x$kzjl1/ugg`~s'~xThlzn_bmvjqYnW=8m7X> gsd-vc)`d9$|~"ixdb3-saebp}%|~Rjnt`]`kphsW`U>>k5Z0.eqb+ta'nf;"z| gvf`5+qcklr#z|Pd`vb[firf}UbS;<i;T2,cw`)zo%l`= xr.et`f7)minty!xr^fbpdYdg|dSdQ82g9V4*aun'xm#jb?.vp,crbd9'}oohv{/vp\`drfWje~byQf_90e?P6(o{l%~k!hl1,tv*aplj;%{imjxu-tvZbf|hUhcx`{_h]:7==R8&myj#|i/fn3*rt(o~nh=#ykcdzw+rtXlh~jSnaznu]j[dbc89:;0<0<8:W3+bta&{l$ka>!ws-dsae6&~nhiuz ws]geqgXkfexRgPaef3456;:7937X> gsd-vc)`d9$|~"ixdb3-saebp}%|~Rjnt`]`kphsW`Ujhi>?01>0:6><]9%l~k }f.eo4+qu'n}oo< xdbg{p*quWmkmRm`uov\mZgcl9:;<1:1399V4*aun'xm#jb?.vp,crbd9'}oohv{/vp\`drfWje~byQf_`fg45674<4856[?/fpe*w`(oe:%{!hwea2*rbdmq~${Qkauc\gjsi|VcTmij?012?1;7402_;#j|i.sd,ci6){%l{im>.vf`a}r({UomyoPcnwmpZoXimn;<=>36?1:?P6(o{l%~k!hl1,tv*aplj;%{imjxu-tvZbf|hUhcx`{_h]b`a67896=2<=7;T2,cw`)zo%l`= xr.et`f7)minty!xr^fbpdYdg|dSdQnde2345:06:30Y=!hrg,qb*ak8'}y#jykc0,t`fc|&}ySio{a^alqkrXaVkoh=>?0=5=56><]9%l~k }f.eo4+qu'n}oo< xdbg{p*quWmkmRm`uov\mZgcl9:;<161389V4*aun'xm#jb?.vp,crbd9'}oohv{/vp\`drfWje~byQf_`fg4567414:?55Z0.eqb+ta'nf;"z| gvf`5+qcklr#z|Pd`vb[firf}UbSljk01238<8382_;#j|i.sd,ci6){%l{im>.vf`a}r({UomyoPcnwmpZoXimn;<=>39?]PS5YT_9;o7X> gsd-vc)`d9$|~"|nm^uq[`hXa8887X> gsd-vc)`d9$|~"ynup,Ifirf}Uhcx`{259V4*aun'xm#jb?.vp,suhsz&Ghcx`{_bmvjq75<2_;#j|i.sd,ci6){%||cz}/LalqkrXkfex?<;;T2,cw`)zo%l`= xr.usjqt(Eje~byQlotlw772<]9%l~k }f.eo4+qu'~zex!BcnwmpZeh}g~?>95Z0.eqb+ta'nf;"z| wqlwv*Kdg|dSnaznu710>S7'nxm"h gm2-sw)pxg~y#@m`uov\gjsi|?8?7X> gsd-vc)`d9$|~"ynup,Ifirf}Uhcx`{7368Q5)`zo$yj"ic0/uq+rvi|{%Fob{at^alqkr?:=1^<"i}f/pe+bj7&~x${}`{r.O`kphsWje~by7=9:W3+bta&{l$ka>!ws-ttkru'DidyczPcnwmpZe~4949o6[?/fpe*w`(oe:%{!xpovq+Heh}g~Tob{at^az858Xz}827X> gsd-vc)`d9$|~"ynup,Ifirf}Uhcx`{_b{?5;4d3\:$kh!rg-dh5(pz&}{by| MbmvjqYdg|dSnw31?]qp7?<]9%l~k }f.eo4+qu'~zex!BcnwmpZeh}g~Tot2=>3a8Q5)`zo$yj"ic0/uq+rvi|{%Fob{at^alqkrXkp692R|{289V4*aun'xm#jb?.vp,suhsz&Ghcx`{_bmvjqYdq595>n5Z0.eqb+ta'nf;"z| wqlwv*Kdg|dSnaznu]`}959W{~956[?/fpe*w`(oe:%{!xpovq+Heh}g~Tob{at^az8185k2_;#j|i.sd,ci6){%||cz}/LalqkrXkfexRmv<5<\vq4>3\:$kh!rg-dh5(pz&}{by| MbmvjqYdg|dSnw35?0`?P6(o{l%~k!hl1,tv*qwf}x$Anaznu]`kphsWjs793Q}t3;8Q5)`zo$yj"ic0/uq+rvi|{%Fob{at^alqkrXkp6=2?m4U1-dvc(un&mg<#y}/vrmpw)JkfexRm`uov\g|:16Vx>45Z0.eqb+ta'nf;"z| wqlwv*Kdg|dSnaznu]`}919:j1^<"i}f/pe+bj7&~x${}`{r.O`kphsWje~byQly=5=[wr512_;#j|i.sd,ci6){%||cz}/LalqkrXkfexRmv<9<1g>S7'nxm"h gm2-sw)pxg~y#@m`uov\gjsi|Vir050Pru0b?P6(o{l%~k!hl1,tv*qwf}x$Anaznu]`kphsWqey0=0=a:W3+bta&{l$ka>!ws-ttkru'DidyczPcnwmpZ~hz5;5>l5Z0.eqb+ta'nf;"z| wqlwv*Kdg|dSnaznu]{kw:56;k0Y=!hrg,qb*ak8'}y#z~ats-Ngjsi|VidyczPxnp?7;4f3\:$kh!rg-dh5(pz&}{by| MbmvjqYdg|dSua}<5<1e>S7'nxm"h gm2-sw)pxg~y#@m`uov\gjsi|Vrd~1;12`9V4*aun'xm#jb?.vp,suhsz&Ghcx`{_bmvjqYg{6=2?o4U1-dvc(un&mg<#y}/vrmpw)JkfexRm`uov\|jt;?78j7X> gsd-vc)`d9$|~"ynup,Ifirf}Uhcx`{_ymq8=85i2_;#j|i.sd,ci6){%||cz}/LalqkrXkfexRv`r=;=6a=R8&myj#|i/fn3*rt(yd~"Clotlw[firf}Usc26>^pw5c=R8&myj#|i/fn3*rt(yd~"m`uov?4;7a3\:$kh!rg-dh5(pz&}{by| cnwmp9799o1^<"i}f/pe+bj7&~x${}`{r.alqkr;:7;m7X> gsd-vc)`d9$|~"ynup,gjsi|595=k5Z0.eqb+ta'nf;"z| wqlwv*eh}g~783?i;T2,cw`)zo%l`= xr.usjqt(kfex1;11g9V4*aun'xm#jb?.vp,suhsz&idycz36?3e?P6(o{l%~k!hl1,tv*qwf}x$ob{at=5=5c=R8&myj#|i/fn3*rt(yd~"m`uov?<;7a3\:$kh!rg-dh5(pz&}{by| cnwmp9?99l1^<"i}f/pe+bj7&~x${}`{r.alqkrX88o0Y=!hrg,qb*ak8'}y#z~ats-`kphsW8;n7X> gsd-vc)`d9$|~"ynup,gjsi|V8:i6[?/fpe*w`(oe:%{!xpovq+firf}U8=h5Z0.eqb+ta'nf;"z| wqlwv*eh}g~T8<k4U1-dvc(un&mg<#y}/vrmpw)dg|dS8?j;T2,cw`)zo%l`= xr.usjqt(kfexR8>e:W3+bta&{l$ka>!ws-ttkru'je~byQ81d9V4*aun'xm#jb?.vp,suhsz&idyczP80g8Q5)`zo$yj"ic0/uq+rvi|{%hcx`{_801?P6(o{l%~k!hl1,tv*qwf}x$ob{at^f28585:2_;#j|i.sd,ci6){%||cz}/bmvjqYc95;5>?5Z0.eqb+ta'nf;"z| wqlwv*eh}g~Th<2=>308Q5)`zo$yj"ic0/uq+rvi|{%hcx`{_e3?7;453\:$kh!rg-dh5(pz&}{by| cnwmpZb64=49>6[?/fpe*w`(oe:%{!xpovq+firf}Uo=1;1239V4*aun'xm#jb?.vp,suhsz&idyczPd0>5:74<]9%l~k }f.eo4+qu'~zex!lotlw[a7;?7897X> gsd-vc)`d9$|~"ynup,gjsi|Vn:050=2:W3+bta&{l$ka>!ws-ttkru'je~byQk1=;=64=R8&myj#|i/fn3*rt(yd~"m`uov\`4Y7:81^<"i}f/pe+bj7&~x${}`{r.alqkrXl8U:><5Z0.eqb+ta'nf;"z| wqlwv*eh}g~Th<Q=209V4*aun'xm#jb?.vp,suhsz&idyczPd0]064=R8&myj#|i/fn3*rt(yd~"m`uov\`4Y3:81^<"i}f/pe+bj7&~x${}`{r.alqkrXl8U>><5Z0.eqb+ta'nf;"z| wqlwv*eh}g~Th<Q9209V4*aun'xm#jb?.vp,suhsz&idyczPd0]464=R8&myj#|i/fn3*rt(yd~"m`uov\`4Y?:81^<"i}f/pe+bj7&~x${}`{r.alqkrXl8U2>?5Z0.eqb+ta'nf;"z| wqlwv*eh}g~Th?2?>308Q5)`zo$yj"ic0/uq+rvi|{%hcx`{_e0?5;453\:$kh!rg-dh5(pz&}{by| cnwmpZb54;49>6[?/fpe*w`(oe:%{!xpovq+firf}Uo>1=1239V4*aun'xm#jb?.vp,suhsz&idyczPd3>7:74<]9%l~k }f.eo4+qu'~zex!lotlw[a4;=7897X> gsd-vc)`d9$|~"ynup,gjsi|Vn90;0=2:W3+bta&{l$ka>!ws-ttkru'je~byQk2=5=67=R8&myj#|i/fn3*rt(yd~"m`uov\`7:?6;80Y=!hrg,qb*ak8'}y#z~ats-`kphsWm8753<>;T2,cw`)zo%l`= xr.usjqt(kfexRj=_102?P6(o{l%~k!hl1,tv*qwf}x$ob{at^f1[4463\:$kh!rg-dh5(pz&}{by| cnwmpZb5W;8:7X> gsd-vc)`d9$|~"ynup,gjsi|Vn9S><>;T2,cw`)zo%l`= xr.usjqt(kfexRj=_502?P6(o{l%~k!hl1,tv*qwf}x$ob{at^f1[0463\:$kh!rg-dh5(pz&}{by| cnwmpZb5W?8:7X> gsd-vc)`d9$|~"ynup,gjsi|Vn9S:<>;T2,cw`)zo%l`= xr.usjqt(kfexRj=_902?P6(o{l%~k!hl1,tv*qwf}x$ob{at^f1[<713\:$kh!rg-nah)cg|~TeR>>6:W3+bta&{l$ahc dnww[lY69>1^<"i}f/pe+hcj'me~xRgP1134?P6(o{l%~k!bel-gkprXaV;:=:5Z0.eqb+ta'dof#iazt^k\57703\:$kh!rg-nah)cg|~TeR?<169V4*aun'xm#`kb/emvpZoX9=;<7X> gsd-vc)jmd%ocxzPi^3652=R8&myj#|i/lgn+air|VcT=;?8;T2,cw`)zo%fi`!kotv\mZ709?1^<"i}f/pe+hcj'me~xRgP2048Q5)`zo$yj"cjm.flqqYnW:;=7X> gsd-vc)jmd%ocxzPi^622>S7'nxm"h mdo,`jssW`U>=;5Z0.eqb+ta'dof#iazt^k\240<]9%l~k }f.ofi*bh}}UbS:?9;T2,cw`)zo%fi`!kotv\mZ>6>2_;#j|i.sd,i`k(lfSdQ6189V4*aun'xm#`kb/emvpZkbe5:5=l5Z0.eqb+ta'dof#iazt^ofi97768k0Y=!hrg,qb*kbe&ndyyQbel>25;7f3\:$kh!rg-nah)cg|~Tahc313<2e>S7'nxm"h mdo,`jssWdof0<=11`9V4*aun'xm#`kb/emvpZkbe5;?2<o4U1-dvc(un&gna"j`uu]nah:6=7;j7X> gsd-vc)jmd%ocxzPmdo?5386i2_;#j|i.sd,i`k(lfS`kb<05=5<=R8&myj#|i/lgn+air|Vgna1?1189V4*aun'xm#`kb/emvpZkbe585=45Z0.eqb+ta'dof#iazt^ofi959901^<"i}f/pe+hcj'me~xRcjm=6=5<=R8&myj#|i/lgn+air|Vgna1;1189V4*aun'xm#`kb/emvpZkbe5<5=45Z0.eqb+ta'dof#iazt^ofi919901^<"i}f/pe+hcj'me~xRcjm=:=5<=R8&myj#|i/lgn+air|Vgna1716d9V4*aun'xm#`kb/f`n*bdjo'miajo!nfg`g+djo&hggRcjm^efj`tf|fx$zlbfd/appw)uidfdc}U?]/pbi+t(~;Uecd`ft/pbi*bw91r:4#|nm0`8Q5)`zo$yj"cjm.vntZtfeVxoSh`>c:W3+bta&{l$ahc tlr\vdkXzmUnb<?<;T2,cw`)zo%ym`Q}d^gm52=R8&myj#|i/scn[wc`g|~Tic?<;T2,cw`)zo%ym`Qxr^gm5a=R8&myj#|i/sqwfim(zmUyyQnssgd65=R8&myj#|i/sqwfim(zmUyyQnssgd[a7582_;#j|i.sd,vvredb%yhR||t^cpv`aXl;;h7X> gsd-vc)u{}hgg"|k_sqw[fijj8n0Y=!hrg,qb*tt|kf`#jPrrv\gjke98o0Y=!hrg,qb*tt|kf`#jPrrv\v`a;87;n7X> gsd-vc)u{}hgg"|k_sqw[wc`484:i6[?/fpe*w`(zz~i`f!}d^pppZtbo585=i5Z0.eqb+ta'{ynae re]qwqYumnU;=i5Z0.eqb+ta'{ynae re]qwqYumnU:=i5Z0.eqb+ta'{ynae re]qwqYumnU9=i5Z0.eqb+ta'{ynae ws]qwqYf{{ol>=5Z0.eqb+ta'{ynae ws]qwqYf{{olSi?=0:W3+bta&{l$~~zmlj-tvZtt|Vkx~hiPd33`?P6(o{l%~k!}su`oo*quW{ySnabb0f8Q5)`zo$yj"||tcnh+rtXzz~Tobcm10g8Q5)`zo$yj"||tcnh+rtXzz~T~hi30?3f?P6(o{l%~k!}su`oo*quW{ySkh<0<2`>S7'nxm"h rrvahn)pzVxxxR|jg^22`>S7'nxm"h rrvahn)pzVxxxR|jg^3b?PUBZVKGEL]l;TQFVZPN[@HGI>5YCB;8RLCPW]S[I>5XE@18S@De3^XBXHQIISQWg>QUA]OTABJJ_@a8SWOSMVGDHHQM1e9[MIOIP$RON->!1!QWQG&7&8*J_NGF5:ZLVF_13QY_@DL8;YQW[BHC?2RXXRXLCc9[[FIUMVCEJB84Xe`\Ma`<PmbT\gbVdppmjh682RoaRCnjnpUawungg;;7Ujb_LkmkwPbzzcdbn5nllmppZcjx}si7lbborv\bpjk>2hjof{d:`bgnswWdkygh|<;bnh`>bf|hUhcx`{(1+g?agsiVidycz'1(g8`drfWje~by&>0(f8`drfWje~by&=)e9geqgXkfex%=&d:fbpdYdg|d$9'k;ecweZeh}g~#9$j4d`vb[firf}"=%i5kauc\gjsi|!="h6jnt`]`kphs 1#o7io{a^alqkr/1 n0hlzn_bmvjq:768:0hlzn_bmvjq:683:5;6jmiugqv3=cag";%;5kio*2-2=cag":<$94dhl+54/03mce$<<&7:fjj-74!>1oec&>4(58`lh/9<#<7iga(04*3>bnf!;<%;5kio*1-3=cag"8%;5kio*7-3=cag">%;5kio*5-3=cag"<%;5kio*;-3=cag"2%;5kio>3:2=cag6:<394dhl?54803mce0<<17:fjj9746>1oec2>4?58`lh;9<4<7iga<04==>bnf5;<6=08;ekm8419>2nbb1?16:fjj949>2nbb1=16:fjj929>2nbb1;16:fjj909>2nbb1916:fjj9>9>2nbb1717:flqq.7!>1ocxz'1(:8`jss 8:"46j`uu*25,><lf$<<&8:flqq.6; 20hb{{(06*<>bh}}":9$64dnww,40.02ndyy&>7(58`jss ;#<7iazt)1*3>bh}}"?%:5kotv+1,1<lf$;'8;emvp-1.?2ndyy&7)69gkpr/1 =0hb{{<1<;?air|5;;255kotv?548?3me~x1?=>99gkpr;9:437iazt=37:==cg|~7=807;emvp9716h1ocxz31683:==cg|~7=:08;emvp979?2ndyy2=>69gkpr;;7=0hb{{<5<4?air|5?5;6j`uu>5:2=cg|~7;394dnww8=803me~x1718:ggmc4iom?0i`~{y208bl`hWnoeio{os]u0Z5+(Qcgecv/CNPF$Bcim{kc.>0/3-46733ocmcRvcny]2O}7?W;igg><4fhdl[}jipV;@t<6P2bnh(coagVmnbh|ntnp\r1Y4$GEEI!@@ND1`=>`nnfUs`cvP1Jz2<Z4ddb&mekaPgdlfvdrhzV|?S>"tc^jbwZoi|Vigg0>#c^jbwZuu{}7; nQ}d^dqat;6$jUcm~Q}d^fbpdYdg|d1<"l_ekm[roc|a7:4!mPh`q\swYci}kTob{at<3/gZ`rdeUm`li|_sqw[sgk58&hSdcldofjqgsafdTxt~j=3.`[pubWlgiiijjd^pfc86+kV}ySk|jq<3/gZstmVndyyQ}su?2(fYrfmoyjaax_mmt95*dWakxSbxjrgnls86+kVzyiaand^nbp`hdq4:'oRj`uu]tmaro582'oRc|gnl\rdj:9%iT~iQkeqvk9465<%iTdl}Puoffvcjh4:'oRfns^coijusWog`0>#c^jbwZtt|4;'oRjnt`]`kphsW~coxe3>1-a\lduX{Ujof3?,b]vw`Ybkj7; nQlololjZekgja6<!mPws]bgnYkg~7; nQ}d^rmpwYpam~c1<>#c^wpaZ`pn}UomyoPcnwmp87+kVbjRocmnqw[`kw|p7; nQ}d^fbpdYdg|dSzgkti?25)eXgoyjaax_mmt95*dW~xT|cz}_vkgpm;68%iT|ah_dosp|Ysqyo6<!mPws]geqgXkfexRyfduj>54*dWyxn`bok_sgdw87+kVndyyQ}su]uei;7$jUcm~Qkauc\gjsi|4:'oR~}of]eqijX|axneQaefcwaZpfd4;;>?"l_vp\``vs`4;;>9"l_qplcZcjx}sTxe|jsi]mabgsmV|j`0;#c^rqkbYbey~rSyf}erj\evubz}U}ma3;,b]kevYqieco1="l_qplcZ`rdeUdk|h^cpw`tsWkg1<>=3-aliuiimg~Tblcj=gkekZ~kfqU:Gu?7_3aoo)eX~hfbhRb`w<2/gZvuadUmekaPtxrf94m91&hS}|`g^dvhiYsqyo6<!mPmdolv|Ysqyo6=!s=e:djbjYdgrT=Fv>8^0`hnYaaoeTkh`jr`vlvZp3W:UsyQ>4:dvhi1<ag~Toae7;oe`fpokl11dzh|ilnub?uthoVof|yw>4:rqkbYbey~rSyf}erj+4,733yxdkRkbpu{\pmtb{a":%<:4psmd[`kw|pUdk|h)0*51=wzfmTi`~{y^vkv`uo :#:86~}of]fiur~W}byi~f'4(37?uthoVof|ywPtipfwm.2!8>0|ah_dosp|Ys`{oxd%8&159svjaXmdzuRzgrdqk,2/6<2zycjQjmqvz[qnumzb#4$?;;qplcZcjx}sTxe|jsi*:-40<x{elShctx]wlwct`531<3?m;qplcZcjx}sTxe|jsi]bwvcu|!:"=o5rne\ahvsqV~c~h}g_`qpawr/9 ;i7}|`g^gntqX|axneQnsrgqp-4.9k1{~biPelrw}ZrozlycSl}|esv+7,7e3yxdkRkbpu{\pmtb{aUj~k}t)6*5g=wzfmTi`~{y^vkv`uoWhyxiz'5(3a?uthoVof|ywPtipfwmYf{zoyx%8&1c9svjaXmdzuRzgrdqk[dutm{~#;$?m;qplcZcjx}sTxe|jsi]bwvcu|!2"=o5rne\ahvsqV~c~h}g_`qpawr/1 ;o7}|`g^gntqX|axneQnsrgqp9?=87;i7}|`g^gntqX|axneQaefcwa-6.9k1{~biPelrw}ZrozlycSckhaug+5,7e3yxdkRkbpu{\pmtb{aUeijo{e)0*5g=wzfmTi`~{y^vkv`uoWgolmyk'3(3a?uthoVof|ywPtipfwmYimnki%:&1c9svjaXmdzuRzgrdqk[kc`i}o#9$?m;qplcZcjx}sTxe|jsi]mabgsm!<"=o5rne\ahvsqV~c~h}g_ogdeqc/? ;i7}|`g^gntqX|axneQaefcwa->.9k1{~biPelrw}ZrozlycSckhaug+=,7c3yxdkRkbpu{\pmtb{aUeijo{e=;94;?<x{elSk{cl018twi`Wog`Rzgrdqk,5/6;2zycjQiumn\pmtb{a":%<=4psmd[cskdV~c~h}g(3+27>vugnUmyabPtipfwm.4!890|ah_gwohZrozlyc$9'>3:rqkbYa}efTxe|jsi*6-45<x{elSk{cl^vkv`uo ?#:?6~}of]eqijX|axne&8)018twi`Wog`Rzgrdqk,=/6;2zycjQiumn\pmtb{a"2%<;4psmd[cskdV~c~h}g<883:4g<x{elSk{cl^vkv`uoWhyxiz'0(3b?uthoVl~`aQ{hsgplZgt{lx$<'>a:rqkbYa}efTxe|jsi]bwvcu|!8"=l5rne\bpjkW}byi~fParqfvq.4!8k0|ah_gwohZrozlycSl}|esv+0,7f3yxdkRhzlm]wlwct`Vkxh|{(4+2e>vugnUmyabPtipfwmYf{zoyx%8&1`9svjaXn|fgSyf}erj\evubz}"<%<o4psmd[cskdV~c~h}g_`qpawr/0 ;j7}|`g^dvhiYs`{oxdRo|sdpw,</6k2zycjQiumn\pmtb{aUj~k}t=;94;7f3yxdkRhzlm]wlwct`Vdnklzj(1+2e>vugnUmyabPtipfwmYimnki%?&1`9svjaXn|fgSyf}erj\j`af|l"9%<o4psmd[cskdV~c~h}g_ogdeqc/; ;j7}|`g^dvhiYs`{oxdR`jg`vf,1/6i2zycjQiumn\pmtb{aUeijo{e)7*5d=wzfmTjxbc_ujqavnXflmjxh&9)0c8twi`Wog`Rzgrdqk[kc`i}o#;$?n;qplcZ`rdeUdk|h^lfcdrb 1#:m6~}of]eqijX|axneQaefcwa-?.9j1{~biPftno[qnumzbTbhintd>:>5813{nToae>0:pg[agsiVidycz'0(33?wbXlh~jSnaznu*2-47<zmUomyoPcnwmp-77!8:0~iQkauc\gjsi|!8"==5}d^fbpdYdg|d$>'>0:pg[agsiVidycz'4(33?wbXlh~jSnaznu*6-46<zmUomyoPcnwmp-0.991yhRjnt`]`kphs >#:<6|k_ecweZeh}g~#4$??;sf\`drfWje~by&6)028vaYci}kTob{at=2=56=ulVnjxlQlotlw846=87;:7jPd`vb[firf}6:<3??;sf\`drfWje~by2>>028vaYci}kTob{at=0=55=ulVnjxlQlotlw868682xoSio{a^alqkr;<7;;7jPd`vb[firf}6>2<>4re]geqgXkfex181119q`Zbf|hUhcx`{<6<24>tcWmkmRm`uov?<;773{nThlzn_bmvjq:>6<1yhRka6:pg[wus;2xxx:5|bhvfvw2<{{y86z}ud;8qkbbzofd{85yamkg2>quWhi`:6y}_bnh55=pzVnjxlQlotlw,5/682}ySio{a^alqkr/9 ;:7z|Pd`vb[firf}":<$??;vp\`drfWje~by&=)028swYci}kTob{at)1*55=pzVnjxlQlotlw,1/682}ySio{a^alqkr/= ;;7z|Pd`vb[firf}"=%<>4ws]geqgXkfex%9&119tvZbf|hUhcx`{(9+24>quWmkmRm`uov+=,773~xThlzn_bmvjq:76890{Qkauc\gjsi|5;;6=0>1:uq[agsiVidycz311<24>quWmkmRm`uov?5;773~xThlzn_bmvjq:568:0{Qkauc\gjsi|595==5xr^fbpdYdg|d090>0:uq[agsiVidycz35?33?rtXlh~jSnaznu>5:46<{UomyoPcnwmp919991|~Rjnt`]`kphs414:<6y}_ecweZeh}g~753;4ws]fj3=pzVxxxpNOpeg2?EF93L187?tS4g90ad=03;8>ij>2;1;37?|f==h6<5a46f90>"3?h0?;95rS4a90ad=03;8>ij>2;1;37?<[8;=69k;:18277bc9;084:<n;R7`>1c3290:??jk1380<24e3m>oi7>51;3xW0c=<mh147?<2ef26?5??;30zY?75;295?7=9l>p_8k54e`9<?74:mn:>7=773;8 10b28;<7[:8b;0xq444281~=?:50:'52b=:;1i8ik50;62>6<39rB?:n5U528745=9;0:57?7:|&2<d<3ll1/8:754ef8m0252900c8:j:18'52`==<20b<9j:198k031290/=:h554:8j41b2810c8;::18'52`==<20b<9j:398k033290/=:h554:8j41b2:10c8;<:18'52`==<20b<9j:598k035290/=:h554:8j41b2<10c8;>:18'52`==<20b<9j:798k037290/=:h554:8j41b2>10c8:i:18'52`==<20b<9j:998k02c290/=:h554:8j41b2010c8:l:18'52`==<20b<9j:`98k04c290/=:h55258j41b2910c8=::18'52`==:=0b<9j:098k053290/=:h55258j41b2;10c8=<:18'52`==:=0b<9j:298k055290/=:h55258j41b2=10c8=>:18'52`==:=0b<9j:498k057290/=:h55258j41b2?10c8<i:18'52`==:=0b<9j:698k04b290/=:h55258j41b2110c8<l:18'52`==:=0b<9j:898k04e290/=:h55258j41b2h10e88<:188k1c52900c9jl:188m02e2900e8:;:188k1da290/=:h54e28j41b2910c9lj:18'52`=<m:0b<9j:098k1dc290/=:h54e28j41b2;10c9ll:18'52`=<m:0b<9j:298k1de290/=:h54e28j41b2=10c9ln:18'52`=<m:0b<9j:498k1d>290/=:h54e28j41b2?10c9l7:18'52`=<m:0b<9j:698k1e0290/=:h54e28j41b2110c9m9:18'52`=<m:0b<9j:898k1e2290/=:h54e28j41b2h10c9m;:18'52`=<m:0b<9j:c98k1e4290/=:h54e28j41b2j10c9m=:18'52`=<m:0b<9j:e98k1e6290/=:h54e28j41b2l10c9m?:18'52`=<m:0b<9j:g98k1d0290/=:h54e28j41b28:07b:m6;29 41a2=n;7c?8e;32?>o31h0;6)?8f;6bf>h6?l0;76g;9883>!70n3>jn6`>7d82?>o3110;6)?8f;6bf>h6?l0976g;9683>!70n3>jn6`>7d80?>o31?0;6)?8f;6bf>h6?l0?76g;9483>!70n3>jn6`>7d86?>o31=0;6)?8f;6bf>h6?l0=76g;9283>!70n3>jn6`>7d84?>o3i;0;6)?8f;6bf>h6?l0376g;a083>!70n3>jn6`>7d8:?>o3i90;6)?8f;6bf>h6?l0j76g;9g83>!70n3>jn6`>7d8a?>o31l0;6)?8f;6bf>h6?l0h76g;9e83>!70n3>jn6`>7d8g?>o31j0;6)?8f;6bf>h6?l0n76g;9c83>!70n3>jn6`>7d8e?>o31;0;6)?8f;6bf>h6?l0:<65f48394?"6?o0?mo5a16g954=<a<8j6=44b54g>5<6290;wE:9c:&2<d<3>m1d=:m50;9~ff7=83;1<7>tH54`?!7?i3i:7bm?:188yg35290257?m6;3f0~N3>j1Q9>4>6za956<6:3;;6<?5e;3:>g<603l1h7?>:0195<<6:3i1=54>0;d9a?b=j3w/=5o54d38 4742kl0(8954ed8 0b=<l:0(<98:05a?l33;3:17b;?8;29?l33>3:17b:8e;29?j3313:17d:71;29?l2aj3:1(<9i:5d`?k70m3:07d:ia;29 41a2=lh7c?8e;38?l2a13:1(<9i:5d`?k70m3807d:i8;29 41a2=lh7c?8e;18?l2a?3:1(<9i:5d`?k70m3>07d:i6;29 41a2=lh7c?8e;78?l2a=3:1(<9i:5d`?k70m3<07d:i4;29 41a2=lh7c?8e;58?l2a;3:1(<9i:5d`?k70m3207d:i2;29 41a2=lh7c?8e;;8?l33:3:17b:j5;29?j33m3:1(<9i:47;?k70m3:07b;:6;29 41a2<?37c?8e;38?j32=3:1(<9i:47;?k70m3807b;:4;29 41a2<?37c?8e;18?j32;3:1(<9i:47;?k70m3>07b;:2;29 41a2<?37c?8e;78?j3293:1(<9i:47;?k70m3<07b;:0;29 41a2<?37c?8e;58?j33n3:1(<9i:47;?k70m3207b;;d;29 41a2<?37c?8e;;8?j33k3:1(<9i:47;?k70m3k07b;=d;29 41a2<9<7c?8e;28?j34=3:1(<9i:414?k70m3;07b;<4;29 41a2<9<7c?8e;08?j34;3:1(<9i:414?k70m3907b;<2;29 41a2<9<7c?8e;68?j3493:1(<9i:414?k70m3?07b;<0;29 41a2<9<7c?8e;48?j35n3:1(<9i:414?k70m3=07b;=e;29 41a2<9<7c?8e;:8?j35k3:1(<9i:414?k70m3307b;=b;29 41a2<9<7c?8e;c8?l3503:1(<9i:40:?k70m3:07d;=7;29 41a2<827c?8e;38?l35>3:1(<9i:40:?k70m3807d;=5;29 41a2<827c?8e;18?l35<3:1(<9i:40:?k70m3>07d;=3;29 41a2<827c?8e;78?l35:3:1(<9i:40:?k70m3<07d;=1;29 41a2<827c?8e;58?l3583:1(<9i:40:?k70m3207d;>f;29 41a2<827c?8e;;8?l31;3:17b:75;29 41a2=2m7c?8e;28?j2?l3:1(<9i:5:e?k70m3;07b:7c;29 41a2=2m7c?8e;08?j2?j3:1(<9i:5:e?k70m3907b:7a;29 41a2=2m7c?8e;68?j2?13:1(<9i:5:e?k70m3?07b:78;29 41a2=2m7c?8e;48?j2??3:1(<9i:5:e?k70m3=07b:76;29 41a2=2m7c?8e;:8?j2?<3:1(<9i:5:e?k70m3307b:73;29 41a2=2m7c?8e;c8?j2b:3:17b:kc;29?l36:3:1(<9i:430?k70m3:07d;>1;29 41a2<;87c?8e;38?l3683:1(<9i:430?k70m3807d;?f;29 41a2<;87c?8e;18?l37m3:1(<9i:430?k70m3>07d;?d;29 41a2<;87c?8e;78?l37k3:1(<9i:430?k70m3<07d;?b;29 41a2<;87c?8e;58?l37i3:1(<9i:430?k70m3207d;?9;29 41a2<;87c?8e;;8?l33j3:17d:j3;29?l2?:3:17d;94;29?j33=3:17b;;a;29?j20n3:17b;;8;29?l33<3:17b:mf;29 41a2=n;7c?8e;28?j2em3:1(<9i:5f3?k70m3;07b:md;29 41a2=n;7c?8e;08?j2ek3:1(<9i:5f3?k70m3907b:mb;29 41a2=n;7c?8e;68?j2ei3:1(<9i:5f3?k70m3?07b:m9;29 41a2=n;7c?8e;48?j2e03:1(<9i:5f3?k70m3=07b:l7;29 41a2=n;7c?8e;:8?j2d>3:1(<9i:5f3?k70m3307b:l5;29 41a2=n;7c?8e;c8?j2d<3:1(<9i:5f3?k70m3h07b:l3;29 41a2=n;7c?8e;a8?j2d:3:1(<9i:5f3?k70m3n07b:l1;29 41a2=n;7c?8e;g8?j2d83:1(<9i:5f3?k70m3l07b:m7;29 41a2=n;7c?8e;33?>i3j?0;6)?8f;6g4>h6?l0:=65f4g294?"6?o0?j<5a16g94>=n<ll1<7*>7g87b4=i9>o1=65f4dg94?"6?o0?j<5a16g96>=n<ln1<7*>7g87b4=i9>o1?65f4da94?"6?o0?j<5a16g90>=n<lh1<7*>7g87b4=i9>o1965f4dc94?"6?o0?j<5a16g92>=n<l31<7*>7g87b4=i9>o1;65f4d:94?"6?o0?j<5a16g9<>=n<l=1<7*>7g87b4=i9>o1565f48c94?"6?o0?mo5a16g94>=n<031<7*>7g87eg=i9>o1=65f48:94?"6?o0?mo5a16g96>=n<0=1<7*>7g87eg=i9>o1?65f48494?"6?o0?mo5a16g90>=n<0?1<7*>7g87eg=i9>o1965f48694?"6?o0?mo5a16g92>=n<091<7*>7g87eg=i9>o1;65f4`094?"6?o0?mo5a16g9<>=n<h;1<7*>7g87eg=i9>o1565f4`294?"6?o0?mo5a16g9e>=n<0l1<7*>7g87eg=i9>o1n65f48g94?"6?o0?mo5a16g9g>=n<0n1<7*>7g87eg=i9>o1h65f48a94?"6?o0?mo5a16g9a>=n<0h1<7*>7g87eg=i9>o1j65f48094?"6?o0?mo5a16g955=<a=3:6=4+16d90dd<f8=n6<?4;h6;4?6=3`?:h7>5$05e>07b3g;<i7>4;h72g?6=,8=m68?j;o34a?7<3`?:n7>5$05e>07b3g;<i7<4;h72e?6=,8=m68?j;o34a?5<3`?:57>5$05e>07b3g;<i7:4;h72<?6=,8=m68?j;o34a?3<3`?:;7>5$05e>07b3g;<i784;h722?6=,8=m68?j;o34a?1<3`?:97>5$05e>07b3g;<i764;h720?6=,8=m68?j;o34a??<3`?;:7>5$05e>0603g;<i7>4;h731?6=,8=m68>8;o34a?7<3`?;87>5$05e>0603g;<i7<4;h737?6=,8=m68>8;o34a?5<3`?;>7>5$05e>0603g;<i7:4;h735?6=,8=m68>8;o34a?3<3`?;<7>5$05e>0603g;<i784;h6eb?6=,8=m68>8;o34a?1<3`>mi7>5$05e>0603g;<i764;h6e`?6=,8=m68>8;o34a??<3f>n:7>5;n6:4?6=3`?9m7>5;c643?6=93:1<v*>8`8`5>N3??1C8;m4ob294?=zj==36=4>:183!7?i3>=h6F;779K03e<g8=h6=44}c66=?6=;3:1<v*>8`8a<>N3??1C8;m4H428 4462<><7)mi:39j11<722c>j7>5;n3;5?6=3th?:94?:283>5}#91k1n55G4648L10d3A?;7)?=1;773>"dn380e8:50;9j1c<722e:4<4?::a00>=8391<7>t$0:b>g><@===7E:9c:J64>"6:80>8:5+cg81?l332900e8h50;9l5=7=831vn98=:186>5<7s-;3m7lk;I642>N3>j1C9=5+1339111<,jl1>6g:4;29?l312900e8h50;9j5=6=831d=5?50;9~f10429086=4?{%3;e?d?3A><:6F;6b9K15=#9;;19994$bd96>o2<3:17d;i:188k4>62900qo::7;291?6=8r.:4l4md:J733=O<?i0D8>4$002>0203-im6?5f5583>>o2>3:17d;i:188m4>72900c<6>:188yg2193:187>50z&2<d<ek2B?;;5G47a8 f`=:2c>87>5;h7e>5<<a82;6=44o0:2>5<<uk>=<7>54;294~"60h0io6F;779K03e<,jl1>6g:4;29?l3a2900e<6?:188k4>62900qo::f;290?6=8r.:4l4mc:J733=O<?i0(nh52:k60?6=3`?m6=44i0:3>5<<g82:6=44}c65e?6=<3:1<v*>8`8ag>N3??1C8;m4$bd96>o2<3:17d;i:188m4>72900c<6>:188yg2113:187>50z&2<d<ek2B?;;5G47a8 f`=:2c>87>5;h7e>5<<a82;6=44o0:2>5<<uk9;>7>54;294~"60h0io6F;779K03e<,jl1;6g:4;29?l3a2900e<6?:188k4>62900qo<6e;291?6=8r.:4l4mb:J733=O<?i0(nh52:k60?6=3`?i6=44i4d94?=n91:1<75`19394?=zj;3m6=4::183!7?i3hi7E:86:J72f=#ko097d;;:188m0d=831b9k4?::k2<5<722e:4<4?::a6d7=83?1<7>t$0:b>gd<@===7E:9c:&`b?4<a<>1<75f5c83>>o2n3:17d?70;29?j7?93:17pl=a383>0<729q/=5o5bc9K020<@=<h7)mi:39j11<722c>n7>5;h7e>5<<a82;6=44o0:2>5<<uk8j?7>55;294~"60h0in6F;779K03e<,jl1>6g:4;29?l3e2900e8h50;9j5=6=831d=5?50;9~f7g3290>6=4?{%3;e?de3A><:6F;6b9'gc<53`??6=44i4`94?=n=o0;66g>8183>>i6080;66sm2`794?3=83:p(<6n:c`8L1113A>=o6*lf;08m02=831b9o4?::k6b?6=3`;3<7>5;n3;5?6=3th9m;4?:483>5}#91k1no5G4648L10d3-im6?5f5583>>o2j3:17d;i:188m4>72900c<6>:188yg4f?3:197>50z&2<d<ej2B?;;5G47a8 f`=:2c>87>5;h7a>5<<a<l1<75f19294?=h91;1<75rb3c;>5<2290;w)?7a;`a?M20>2B?:n5+cg81?l332900e8l50;9j1c<722c:4=4?::m2<4<722wi>l>50;794?6|,82j6ol4H555?M21k2.hj7<4i4694?=n=k0;66g:f;29?l7?83:17b?71;29?xd4?l0;694?:1y'5=g=jj1C8:84H54`?!ea2;1b994?::k6b?6=3`;3<7>5;n3;5?6=3th8;i4?:583>5}#91k1nn5G4648L10d3-im6?5f5583>>o2n3:17d?70;29?j7?93:17pl<b183>1<729q/=5o5b89K020<@=<h7)mi:39j11<722c>n7>5;h7e>5<<g82:6=44}c1a5?6=<3:1<v*>8`8a=>N3??1C8;m4$bd96>o2<3:17d;m:188m0`=831d=5?50;9~f6d4290?6=4?{%3;e?d>3A><:6F;6b9'gc<53`??6=44i4`94?=n=o0;66a>8083>>{e;k>1<7:50;2x 4>f2k30D999;I65g>"dn380e8:50;9j1g<722c>j7>5;n3;5?6=3th8n84?:583>5}#91k1n45G4648L10d3-im6?5f5583>>o2j3:17d;i:188k4>62900qo=m6;290?6=8r.:4l4m9:J733=O<?i0(nh52:k60?6=3`?i6=44i4d94?=h91;1<75rb2`4>5<3290;w)?7a;`:?M20>2B?:n5+cg81?l332900e8l50;9j1c<722e:4<4?::a7g>=83>1<7>t$0:b>g?<@===7E:9c:&`b?4<a<>1<75f5c83>>o2n3:17b?71;29?xd4j00;694?:1y'5=g=j01C8:84H54`?!ea2;1b994?::k6f?6=3`?m6=44o0:2>5<<uk9im7>54;294~"60h0i56F;779K03e<,jl1>6g:4;29?l3e2900e8h50;9l5=7=831vn>l=:187>5<7s-;3m7l6;I642>N3>j1/ok4=;h77>5<<a<h1<75f5g83>>i6080;66sm29;94?5=83:p(<6n:03:?M20>2B?:n5+cg800>od;3:17dm;:188k41f2900qo<70;290?6=8r.:4l4>239K020<@=<h7d;7:188m37=831b=5=50;9l52g=831vn?7<:180>5<7s-;3m7:85:J733=O<?i0e8650;9j542=831d=:o50;9~f7>f29086=4?{%3;e?7612B?;;5G47a8 f`=;=1bo>4?::k`0?6=3f;<m7>5;|`1<4<72=0;6=u+19c9574<@===7E:9c:k6<?6=3`<:6=44i0:0>5<<g8=j6=44}c0:0?6=;3:1<v*>8`8730=O<><0D98l;h7;>5<<a8;?6=44o05b>5<<uk83n7>53;294~"60h0:=45G4648L10d3-im6>:4ib194?=nk=0;66a>7`83>>{e:181<7:50;2x 4>f28897E:86:J72f=n=10;66g91;29?l7?;3:17b?8a;29?xd51<0;6>4?:1y'5=g=<>?0D999;I65g>o203:17d?>4;29?j70i3:17pl=8b83>6<729q/=5o510;8L1113A>=o6*lf;17?le42900en:50;9l52g=831vn?6<:187>5<7s-;3m7?=2:J733=O<?i0e8650;9j24<722c:4>4?::m23d<722wi>4850;194?6|,82j699:;I642>N3>j1b954?::k251<722e:;l4?::a6=b=8391<7>t$0:b>47>3A><:6F;6b9'gc<4<2ch?7>5;ha7>5<<g8=j6=44}c0;0?6=<3:1<v*>8`8267=O<><0D98l;h7;>5<<a?;1<75f19194?=h9>k1<75rb3;4>5<4290;w)?7a;641>N3??1C8;m4i4:94?=n98>1<75`16c94?=zj;2n6=4<:183!7?i3;:56F;779K03e<,jl1?95fc283>>od<3:17b?8a;29?xd50<0;694?:1y'5=g=9;80D999;I65g>o203:17d8>:188m4>42900c<9n:188yg4>03:1?7>50z&2<d<3?<1C8:84H54`?l3?2900e<?;:188k41f2900qo<7f;297?6=8r.:4l4>189K020<@=<h7)mi:268mf5=831bo94?::m23d<722wi>5850;694?6|,82j6<<=;I642>N3>j1b954?::k55?6=3`;3?7>5;n34e?6=3th9544?:283>5}#91k18:;4H555?M21k2c>47>5;h320?6=3f;<m7>5;|`1=5<72:0;6=u+19c954?<@===7E:9c:&`b?533`i86=44ib694?=h9>k1<75rb3:4>5<3290;w)?7a;316>N3??1C8;m4i4:94?=n>80;66g>8283>>i6?h0;66sm28c94?5=83:p(<6n:556?M20>2B?:n5f5983>>o69=0;66a>7`83>>{e:0;1<7=50;2x 4>f28;27E:86:J72f=#ko0886gl3;29?le32900c<9n:188yg4?03:187>50z&2<d<6:;1C8:84H54`?l3?2900e;?50;9j5=5=831d=:o50;9~f7?e29086=4?{%3;e?20=2B?;;5G47a8m0>=831b=<:50;9l52g=831vn?7=:180>5<7s-;3m7?>9:J733=O<?i0(nh5359jg6<722ch87>5;n34e?6=3th95n4?:283>5}#91k18:;4H555?M21k2c>47>5;h320?6=3f;<m7>5;|`0=g<72:0;6=u+19c954?<@===7E:9c:&`b?533`i86=44ib694?=h9>k1<75rb2;1>5<3290;w)?7a;316>N3??1C8;m4i4:94?=n>80;66g>8283>>i6?h0;66sm3`794?5=83:p(<6n:556?M20>2B?:n5f5983>>o69=0;66a>7`83>>{e;0i1<7=50;2x 4>f28;27E:86:J72f=#ko0886gl3;29?le32900c<9n:188yg5>;3:187>50z&2<d<6:;1C8:84H54`?l3?2900e;?50;9j5=5=831d=:o50;9~f6g129086=4?{%3;e?20=2B?;;5G47a8m0>=831b=<:50;9l52g=831vn>7k:180>5<7s-;3m7?>9:J733=O<?i0(nh5359jg6<722ch87>5;n34e?6=3th8594?:583>5}#91k1=?<4H555?M21k2c>47>5;h42>5<<a8286=44o05b>5<<uk9j;7>53;294~"60h0?;85G4648L10d3`?36=44i037>5<<g8=j6=44}c1:a?6=;3:1<v*>8`825<=O<><0D98l;%ae>62<aj91<75fc583>>i6?h0;66sm38794?2=83:p(<6n:001?M20>2B?:n5f5983>>o193:17d?73;29?j70i3:17pl<a983>6<729q/=5o54678L1113A>=o6g:8;29?l76<3:17b?8a;29?xd41o0;6>4?:1y'5=g=9830D999;I65g>"dn39?7dm<:188mf2=831d=:o50;9~f6?1290?6=4?{%3;e?75:2B?;;5G47a8m0>=831b:<4?::k2<6<722e:;l4?::a7d?=8391<7>t$0:b>1123A><:6F;6b9j1=<722c:=94?::m23d<722wi?l>50;194?6|,82j6<?6;I642>N3>j1/ok4<4:k`7?6=3`i?6=44o05b>5<<uk92;7>54;294~"60h0:>?5G4648L10d3`?36=44i7394?=n9191<75`16c94?=zj:kj6=4<:183!7?i3><96F;779K03e<a<21<75f10694?=h9>k1<75rb2c2>5<4290;w)?7a;32=>N3??1C8;m4$bd971=nk:0;66gl4;29?j70i3:17pl<9983>1<729q/=5o51308L1113A>=o6g:8;29?l062900e<6<:188k41f2900qo=nb;297?6=8r.:4l4;749K020<@=<h7d;7:188m4732900c<9n:188yg5f:3:1?7>50z&2<d<6901C8:84H54`?!ea2:>0en=50;9jg1<722e:;l4?::a7<?=83>1<7>t$0:b>4453A><:6F;6b9j1=<722c==7>5;h3;7?6=3f;<m7>5;|`0ef<72:0;6=u+19c9023<@===7E:9c:k6<?6=3`;:87>5;n34e?6=3th8m>4?:283>5}#91k1=<74H555?M21k2.hj7=;;ha0>5<<aj>1<75`16c94?=zj:3j6=4;:183!7?i3;9>6F;779K03e<a<21<75f6083>>o60:0;66a>7`83>>{e;hn1<7=50;2x 4>f2==>7E:86:J72f=n=10;66g>1583>>i6?h0;66sm3`694?5=83:p(<6n:03:?M20>2B?:n5+cg800>od;3:17dm;:188k41f2900qo=ne;297?6=8r.:4l4;749K020<@=<h7d;7:188m4732900c<9n:188yg4b:3:187>50z&2<d<6:;1C8:84H54`?l3?2900e;?50;9j5=5=831d=:o50;9~f7c6290?6=4?{%3;e?75:2B?;;5G47a8m0>=831b:<4?::k2<6<722e:;l4?::a6`6=83>1<7>t$0:b>4453A><:6F;6b9j1=<722c==7>5;h3;7?6=3f;<m7>5;|`1`c<72=0;6=u+19c9574<@===7E:9c:k6<?6=3`<:6=44i0:0>5<<g8=j6=44}c0ga?6=<3:1<v*>8`8267=O<><0D98l;h7;>5<<a?;1<75f19194?=h9>k1<75rb3d6>5<3290;w)?7a;316>N3??1C8;m4i4:94?=n>80;66g>8283>>i6?h0;66sm2g694?2=83:p(<6n:001?M20>2B?:n5f5983>>o193:17d?73;29?j70i3:17pl=f283>1<729q/=5o51308L1113A>=o6g:8;29?l062900e<6<:188k41f2900qo<i2;290?6=8r.:4l4>239K020<@=<h7d;7:188m37=831b=5=50;9l52g=831vn?h>:187>5<7s-;3m7?=2:J733=O<?i0e8650;9j24<722c:4>4?::m23d<722wi?8j50;694?6|,82j6<<=;I642>N3>j1b954?::k55?6=3`;3?7>5;n34e?6=3th89n4?:583>5}#91k1=?<4H555?M21k2c>47>5;h42>5<<a8286=44o05b>5<<uk9>n7>54;294~"60h0:>?5G4648L10d3`?36=44i7394?=n9191<75`16c94?=zj:?j6=4;:183!7?i3;9>6F;779K03e<a<21<75f6083>>o60:0;66a>7`83>>{e;<31<7:50;2x 4>f28897E:86:J72f=n=10;66g91;29?l7?;3:17b?8a;29?xd4?90;694?:1y'5=g=9;80D999;I65g>o203:17d8>:188m4>42900c<9n:188yg51n3:187>50z&2<d<6:;1C8:84H54`?l3?2900e;?50;9j5=5=831d=:o50;9~f60b290?6=4?{%3;e?75:2B?;;5G47a8m0>=831b:<4?::k2<6<722e:;l4?::a73b=83>1<7>t$0:b>4453A><:6F;6b9j1=<722c==7>5;h3;7?6=3f;<m7>5;|`02f<72=0;6=u+19c9574<@===7E:9c:k6<?6=3`<:6=44i0:0>5<<g8=j6=44}c3a4?6=<3:1<v*>8`8a=>N3??1C8;m4$bd96>o2<3:17d;m:188m0`=831d=5?50;9~f4ga290?6=4?{%3;e?d>3A><:6F;6b9'gc<53`??6=44i4`94?=n=o0;66a>8083>>{e9ho1<7:50;2x 4>f2k30D999;I65g>"dn380e8:50;9j1g<722c>j7>5;n3;5?6=3th:mi4?:583>5}#91k1n45G4648L10d3-im6?5f5583>>o2j3:17d;i:188k4>62900qo?nc;290?6=8r.:4l4m9:J733=O<?i0(nh52:k60?6=3`?i6=44i4d94?=h91;1<75rb0ca>5<3290;w)?7a;`:?M20>2B?:n5+cg81?l332900e8l50;9j1c<722e:4<4?::a5dg=83>1<7>t$0:b>g?<@===7E:9c:&`b?4<a<>1<75f5c83>>o2n3:17b?71;29?xd6i00;694?:1y'5=g=j01C8:84H54`?!ea2;1b994?::k6f?6=3`?m6=44o0:2>5<<uk;j47>54;294~"60h0i56F;779K03e<,jl1>6g:4;29?l3e2900e8h50;9l5=7=831vn<o8:187>5<7s-;3m7l6;I642>N3>j1/ok4=;h77>5<<a<h1<75f5g83>>i6080;66sm20f94?2=83:p(<6n:c;8L1113A>=o6*lf;08m02=831b9o4?::k6b?6=3f;3=7>5;|`15f<72=0;6=u+19c9f<=O<><0D98l;%ae>7=n==0;66g:b;29?l3a2900c<6>:188yg46j3:187>50z&2<d<e12B?;;5G47a8 f`=:2c>87>5;h7a>5<<a<l1<75`19394?=zj;;j6=4;:183!7?i3h27E:86:J72f=#ko097d;;:188m0d=831b9k4?::m2<4<722wi><750;694?6|,82j6o74H555?M21k2.hj7<4i4694?=n=k0;66g:f;29?j7?93:17pl=1983>1<729q/=5o5b89K020<@=<h7)mi:39j11<722c>n7>5;h7e>5<<g82:6=44}c023?6=<3:1<v*>8`8a=>N3??1C8;m4$bd96>o2<3:17d;m:188m0`=831d=5?50;9~f771290?6=4?{%3;e?d>3A><:6F;6b9'gc<53`??6=44i4`94?=n=o0;66a>8083>>{e:8?1<7:50;2x 4>f2k30D999;I65g>"dn380e8:50;9j1g<722c>j7>5;n3;5?6=3th9=94?:583>5}#91k1n45G4648L10d3-im6?5f5583>>o2j3:17d;i:188k4>62900qo<9d;290?6=8r.:4l4m9:J733=O<?i0(nh52:k60?6=3`?i6=44i4d94?=h91;1<75rb34`>5<3290;w)?7a;`:?M20>2B?:n5+cg81?l332900e8l50;9j1c<722e:4<4?::a63d=83>1<7>t$0:b>g?<@===7E:9c:&`b?4<a<>1<75f5c83>>o2n3:17b?71;29?xd5>h0;694?:1y'5=g=j01C8:84H54`?!ea2;1b994?::k6f?6=3`?m6=44o0:2>5<<uk8=57>54;294~"60h0i56F;779K03e<,jl1>6g:4;29?l3e2900e8h50;9l5=7=831vn?87:187>5<7s-;3m7l6;I642>N3>j1/ok4=;h77>5<<a<h1<75f5g83>>i6080;66sm27594?2=83:p(<6n:c;8L1113A>=o6*lf;08m02=831b9o4?::k6b?6=3f;3=7>5;|`123<72=0;6=u+19c9f<=O<><0D98l;%ae>7=n==0;66g:b;29?l3a2900c<6>:188yg41=3:187>50z&2<d<e12B?;;5G47a8 f`=:2c>87>5;h7a>5<<a<l1<75`19394?=zj;<?6=4;:183!7?i3h27E:86:J72f=#ko097d;;:188m0d=831b9k4?::m2<4<722wi>=>50;694?6|,82j6o74H555?M21k2.hj7<4i4694?=n=k0;66g:f;29?j7?93:17pl>fg83>1<729q/=5o5b89K020<@=<h7)mi:39j11<722c>n7>5;h7e>5<<g82:6=44}c3ea?6=<3:1<v*>8`8a=>N3??1C8;m4$bd96>o2<3:17d;m:188m0`=831d=5?50;9~f4`c290?6=4?{%3;e?d>3A><:6F;6b9'gc<53`??6=44i4`94?=n=o0;66a>8083>>{e9oi1<7:50;2x 4>f2k30D999;I65g>"dn380e8:50;9j1g<722c>j7>5;n3;5?6=3th:jo4?:583>5}#91k1n45G4648L10d3-im6?5f5583>>o2j3:17d;i:188k4>62900qo?ia;290?6=8r.:4l4m9:J733=O<?i0(nh52:k60?6=3`?i6=44i4d94?=h91;1<75rb0d:>5<3290;w)?7a;`:?M20>2B?:n5+cg81?l332900e8l50;9j1c<722e:4<4?::a5c>=83>1<7>t$0:b>g?<@===7E:9c:&`b?4<a<>1<75f5c83>>o2n3:17b?71;29?xd6n>0;694?:1y'5=g=j01C8:84H54`?!ea2;1b994?::k6f?6=3`?m6=44o0:2>5<<uk8>57>54;294~"60h0i56F;779K03e<@<:0(<<>:464?!ea2;1b994?::k6f?6=3`?m6=44o0:2>5<<uk8>47>54;294~"60h0i56F;779K03e<@<:0(<<>:464?!ea2;1b994?::k6f?6=3`?m6=44o0:2>5<<uk8>;7>54;294~"60h0i56F;779K03e<@<:0(<<>:464?!ea2;1b994?::k6f?6=3`?m6=44o0:2>5<<uk8>:7>54;294~"60h0i56F;779K03e<@<:0(<<>:464?!ea2;1b994?::k6f?6=3`?m6=44o0:2>5<<uk8>97>54;294~"60h0i56F;779K03e<@<:0(<<>:464?!ea2;1b994?::k6f?6=3`?m6=44o0:2>5<<uk8>87>54;294~"60h0i56F;779K03e<@<:0(<<>:464?!ea2;1b994?::k6f?6=3`?m6=44o0:2>5<<uk8>?7>54;294~"60h0i56F;779K03e<@<:0(<<>:464?!ea2;1b994?::k6f?6=3`?m6=44o0:2>5<<uk8>>7>54;294~"60h0i56F;779K03e<@<:0(<<>:464?!ea2;1b994?::k6f?6=3`?m6=44o0:2>5<<uk8>=7>54;294~"60h0i56F;779K03e<@<:0(<<>:464?!ea2;1b994?::k6f?6=3`?m6=44o0:2>5<<uk8><7>54;294~"60h0i56F;779K03e<@<:0(<<>:464?!ea2;1b994?::k6f?6=3`?m6=44o0:2>5<<uk;no7>54;294~"60h0i56F;779K03e<@<:0(<<>:464?!ea2;1b994?::k6f?6=3`?m6=44o0:2>5<<uk;nn7>54;294~"60h0i56F;779K03e<@<:0(<<>:464?!ea2;1b994?::k6f?6=3`?m6=44o0:2>5<<uk;nm7>54;294~"60h0i56F;779K03e<@<:0(<<>:464?!ea2;1b994?::k6f?6=3`?m6=44o0:2>5<<uk;n57>54;294~"60h0i56F;779K03e<@<:0(<<>:464?!ea2;1b994?::k6f?6=3`?m6=44o0:2>5<<uk;n47>54;294~"60h0i56F;779K03e<@<:0(<<>:464?!ea2;1b994?::k6f?6=3`?m6=44o0:2>5<<uk;n;7>54;294~"60h0i56F;779K03e<@<:0(<<>:464?!ea2;1b994?::k6f?6=3`?m6=44o0:2>5<<uk;n:7>54;294~"60h0i56F;779K03e<@<:0(<<>:464?!ea2;1b994?::k6f?6=3`?m6=44o0:2>5<<uk;n97>54;294~"60h0i56F;779K03e<@<:0(<<>:464?!ea2;1b994?::k6f?6=3`?m6=44o0:2>5<<uk;n87>54;294~"60h0i56F;779K03e<@<:0(<<>:464?!ea2;1b994?::k6f?6=3`?m6=44o0:2>5<<uk;n?7>54;294~"60h0i56F;779K03e<@<:0(<<>:464?!ea2;1b994?::k6f?6=3`?m6=44o0:2>5<<uk;o47>54;294~"60h0i56F;779K03e<,jl1>6g:4;29?l3e2900e8h50;9l5=7=831vn<j8:187>5<7s-;3m7l6;I642>N3>j1/ok4=;h77>5<<a<h1<75f5g83>>i6080;66sm1e494?2=83:p(<6n:c;8L1113A>=o6*lf;08m02=831b9o4?::k6b?6=3f;3=7>5;|`2`0<72=0;6=u+19c9f<=O<><0D98l;%ae>7=n==0;66g:b;29?l3a2900c<6>:188yg7c<3:187>50z&2<d<e12B?;;5G47a8 f`=:2c>87>5;h7a>5<<a<l1<75`19394?=zj8n86=4;:183!7?i3h27E:86:J72f=#ko097d;;:188m0d=831b9k4?::m2<4<722wi=i<50;694?6|,82j6o74H555?M21k2.hj7<4i4694?=n=k0;66g:f;29?j7?93:17pl>d083>1<729q/=5o5b89K020<@=<h7)mi:39j11<722c>n7>5;h7e>5<<g82:6=44}c3g4?6=<3:1<v*>8`8a=>N3??1C8;m4$bd96>o2<3:17d;m:188m0`=831d=5?50;9~f4ea290?6=4?{%3;e?d>3A><:6F;6b9'gc<53`??6=44i4`94?=n=o0;66a>8083>>{e:=?1<7:50;2x 4>f2k30D999;I65g>"dn380e8:50;9j1g<722c>j7>5;n3;5?6=3th9894?:583>5}#91k1n45G4648L10d3-im6?5f5583>>o2j3:17d;i:188k4>62900qo<;3;290?6=8r.:4l4m9:J733=O<?i0(nh52:k60?6=3`?i6=44i4d94?=h91;1<75rb361>5<3290;w)?7a;`:?M20>2B?:n5+cg81?l332900e8l50;9j1c<722e:4<4?::a617=83>1<7>t$0:b>g?<@===7E:9c:&`b?4<a<>1<75f5c83>>o2n3:17b?71;29?xd5<90;694?:1y'5=g=j01C8:84H54`?!ea2;1b994?::k6f?6=3`?m6=44o0:2>5<<uk88j7>54;294~"60h0i56F;779K03e<,jl1>6g:4;29?l3e2900e8h50;9l5=7=831vn?=j:187>5<7s-;3m7l6;I642>N3>j1/ok4=;h77>5<<a<h1<75f5g83>>i6080;66sm22f94?2=83:p(<6n:c;8L1113A>=o6*lf;08m02=831b9o4?::k6b?6=3f;3=7>5;|`17f<72=0;6=u+19c9f<=O<><0D98l;%ae>7=n==0;66g:b;29?l3a2900c<6>:188yg5383:197>50z&2<d<ei2B?;;5G47a8 f`=:2c>87>5;h75>5<<a<h1<75f5g83>>i6080;66sm32d94?3=83:p(<6n:cc8L1113A>=o6*lf;08m02=831b9;4?::k6f?6=3`?m6=44o0:2>5<<uk98h7>55;294~"60h0im6F;779K03e<,jl1>6g:4;29?l312900e8l50;9j1c<722e:4<4?::a76e=83?1<7>t$0:b>gg<@===7E:9c:&`b?4<a<>1<75f5783>>o2j3:17d;i:188k4>62900qo=<e;291?6=8r.:4l4ma:J733=O<?i0(nh52:k60?6=3`?=6=44i4`94?=n=o0;66a>8083>>{e;:h1<7;50;2x 4>f2kk0D999;I65g>"dn380e8:50;9j13<722c>n7>5;h7e>5<<g82:6=44}c10e?6==3:1<v*>8`8ae>N3??1C8;m4$bd96>o2<3:17d;9:188m0d=831b9k4?::m2<4<722wi?>650;794?6|,82j6oo4H555?M21k2.hj7<4i4694?=n=?0;66g:b;29?l3a2900c<6>:188yg54?3:197>50z&2<d<el2B?;;5G47a8 f`=?2c>87>5;h75>5<<a<l1<75f19294?=h91;1<75rb21:>5<2290;w)?7a;`b?M20>2B?:n5+cg81?l332900e8850;9j1g<722c>j7>5;n3;5?6=3th8>o4?:283>5}#91k18:;4H555?M21k2c>47>5;h320?6=3f;<m7>5;|`06d<72:0;6=u+19c9023<@===7E:9c:k6<?6=3`;:87>5;n34e?6=3th8>=4?:583>5}#91k1=?<4H555?M21k2c>47>5;h42>5<<a8286=44o05b>5<<uk9957>53;294~"60h0?;85G4648L10d3`?36=44i037>5<<g8=j6=44}c12a?6=<3:1<v*>8`8267=O<><0D98l;h7;>5<<a?;1<75f19194?=h9>k1<75rb20;>5<4290;w)?7a;641>N3??1C8;m4i4:94?=n98>1<75`16c94?=zj:;h6=4;:183!7?i3;9>6F;779K03e<a<21<75f6083>>o60:0;66a>7`83>>{e;;=1<7=50;2x 4>f2==>7E:86:J72f=n=10;66g>1583>>i6?h0;66sm30c94?2=83:p(<6n:001?M20>2B?:n5f5983>>o193:17d?73;29?j70i3:17pl<2783>6<729q/=5o54678L1113A>=o6g:8;29?l76<3:17b?8a;29?xd4910;694?:1y'5=g=9;80D999;I65g>o203:17d8>:188m4>42900c<9n:188yg55=3:1?7>50z&2<d<3?<1C8:84H54`?l3?2900e<?;:188k41f2900qo=>6;290?6=8r.:4l4>239K020<@=<h7d;7:188m37=831b=5=50;9l52g=831vn><;:180>5<7s-;3m7:85:J733=O<?i0e8650;9j542=831d=:o50;9~f673290?6=4?{%3;e?75:2B?;;5G47a8m0>=831b:<4?::k2<6<722e:;l4?::a775=8391<7>t$0:b>1123A><:6F;6b9j1=<722c:=94?::m23d<722wi?<<50;694?6|,82j6<<=;I642>N3>j1b954?::k55?6=3`;3?7>5;n34e?6=3th8>?4?:283>5}#91k18:;4H555?M21k2c>47>5;h320?6=3f;<m7>5;|`055<72=0;6=u+19c9574<@===7E:9c:k6<?6=3`<:6=44i0:0>5<<g8=j6=44}c160?6==3:1<v*>8`8ae>N3??1C8;m4$bd96>o2<3:17d;9:188m0d=831b9k4?::m2<4<722wi?8=50;794?6|,82j6oo4H555?M21k2.hj7<4i4694?=n=?0;66g:b;29?l3a2900c<6>:188yg52:3:197>50z&2<d<ei2B?;;5G47a8 f`=:2c>87>5;h75>5<<a<h1<75f5g83>>i6080;66sm34394?3=83:p(<6n:cc8L1113A>=o6*lf;08m02=831b9;4?::k6f?6=3`?m6=44o0:2>5<<uk9><7>55;294~"60h0im6F;779K03e<,jl1>6g:4;29?l312900e8l50;9j1c<722e:4<4?::a71`=83?1<7>t$0:b>gg<@===7E:9c:&`b?4<a<>1<75f5783>>o2j3:17d;i:188k4>62900qo=;e;291?6=8r.:4l4ma:J733=O<?i0(nh52:k60?6=3`?=6=44i4`94?=n=o0;66a>8083>>{e;=n1<7;50;2x 4>f2kk0D999;I65g>"dn380e8:50;9j13<722c>n7>5;h7e>5<<g82:6=44}c17g?6==3:1<v*>8`8ae>N3??1C8;m4$bd96>o2<3:17d;9:188m0d=831b9k4?::m2<4<722wi?9l50;794?6|,82j6oo4H555?M21k2.hj7<4i4694?=n=?0;66g:b;29?l3a2900c<6>:188yg4c:3:187>50z&2<d<e12B?;;5G47a8 f`=:2c>87>5;h7a>5<<a<l1<75`19394?=zj;im6=4;:183!7?i3h27E:86:J72f=#ko097d;;:188m0d=831b9k4?::m2<4<722wi>i750;694?6|,82j6o74H555?M21k2.hj7<4i4694?=n=k0;66g:f;29?j7?93:17pl=d783>1<729q/=5o5bb9K020<@=<h7)mi:69j11<722c>j7>5;h3;4?6=3f;3=7>5;|`1`0<72=0;6=u+19c9ff=O<><0D98l;%ae>2=n==0;66g:f;29?l7?83:17b?71;29?xd38=0;684?:1y'5=g=jh1C8:84H54`?!ea2;1b994?::k62?6=3`?i6=44i4d94?=h91;1<75rb520>5<2290;w)?7a;`b?M20>2B?:n5+cg81?l332900e8850;9j1g<722c>j7>5;n3;5?6=3th?<<4?:483>5}#91k1nl5G4648L10d3-im6?5f5583>>o2>3:17d;m:188m0`=831d=5?50;9~f167290>6=4?{%3;e?df3A><:6F;6b9'gc<53`??6=44i4494?=n=k0;66g:f;29?j7?93:17pl;0383>0<729q/=5o5b`9K020<@=<h7)mi:39j11<722c>:7>5;h7a>5<<a<l1<75`19394?=zj:lm6=4::183!7?i3hj7E:86:J72f=#ko097d;;:188m00=831b9o4?::k6b?6=3f;3=7>5;|`0b`<72<0;6=u+19c9fd=O<><0D98l;%ae>7=n==0;66g:6;29?l3e2900e8h50;9l5=7=831vn>hl:186>5<7s-;3m7lk;I642>N3>j1/ok48;h77>5<<a<<1<75f5g83>>o6090;66a>8083>>{e;oh1<7;50;2x 4>f2kk0D999;I65g>"dn380e8:50;9j13<722c>n7>5;h7e>5<<g82:6=44}c1e`?6==3:1<v*>8`8ae>N3??1C8;m4$bd96>o2<3:17d;9:188m0d=831b9k4?::m2<4<722wi?hh50;194?6|,82j699:;I642>N3>j1b954?::k251<722e:;l4?::a7`c=8391<7>t$0:b>1123A><:6F;6b9j1=<722c:=94?::m23d<722wi?h:50;694?6|,82j6<<=;I642>N3>j1b954?::k55?6=3`;3?7>5;n34e?6=3th8ii4?:283>5}#91k18:;4H555?M21k2c>47>5;h320?6=3f;<m7>5;|`0a7<72=0;6=u+19c9574<@===7E:9c:k6<?6=3`<:6=44i0:0>5<<g8=j6=44}c1fg?6=;3:1<v*>8`8730=O<><0D98l;h7;>5<<a8;?6=44o05b>5<<uk9n<7>54;294~"60h0:>?5G4648L10d3`?36=44i7394?=n9191<75`16c94?=zj:oi6=4<:183!7?i3><96F;779K03e<a<21<75f10694?=h9>k1<75rb2ff>5<3290;w)?7a;316>N3??1C8;m4i4:94?=n>80;66g>8283>>i6?h0;66sm3dc94?5=83:p(<6n:556?M20>2B?:n5f5983>>o69=0;66a>7`83>>{e;mi1<7:50;2x 4>f28897E:86:J72f=n=10;66g91;29?l7?;3:17b?8a;29?xd4m00;6>4?:1y'5=g=<>?0D999;I65g>o203:17d?>4;29?j70i3:17pl<d`83>1<729q/=5o51308L1113A>=o6g:8;29?l062900e<6<:188k41f2900qo=j8;297?6=8r.:4l4;749K020<@=<h7d;7:188m4732900c<9n:188yg5c03:187>50z&2<d<6:;1C8:84H54`?l3?2900e;?50;9j5=5=831d=:o50;9~f6c029086=4?{%3;e?20=2B?;;5G47a8m0>=831b=<:50;9l52g=831vn>j9:187>5<7s-;3m7?=2:J733=O<?i0e8650;9j24<722c:4>4?::m23d<722wi?h850;194?6|,82j699:;I642>N3>j1b954?::k251<722e:;l4?::a7a2=83>1<7>t$0:b>4453A><:6F;6b9j1=<722c==7>5;h3;7?6=3f;<m7>5;|`754<72<0;6=u+19c9fd=O<><0D98l;%ae>7=n==0;66g:6;29?l3e2900e8h50;9l5=7=831vn9>i:186>5<7s-;3m7lk;I642>N3>j1/ok48;h77>5<<a<<1<75f5g83>>o6090;66a>8083>>{e<8:1<7;50;2x 4>f2kk0D999;I65g>"dn380e8:50;9j13<722c>n7>5;h7e>5<<g82:6=44}c626?6==3:1<v*>8`8ae>N3??1C8;m4$bd96>o2<3:17d;9:188m0d=831b9k4?::m2<4<722wi8<=50;794?6|,82j6oo4H555?M21k2.hj7<4i4694?=n=?0;66g:b;29?l3a2900c<6>:188yg26>3:197>50z&2<d<ei2B?;;5G47a8 f`=:2c>87>5;h75>5<<a<h1<75f5g83>>i6080;66sm40694?3=83:p(<6n:cc8L1113A>=o6*lf;08m02=831b9;4?::k6f?6=3`?m6=44o0:2>5<<uk>:97>55;294~"60h0im6F;779K03e<,jl1>6g:4;29?l312900e8l50;9j1c<722e:4<4?::a041=83?1<7>t$0:b>gg<@===7E:9c:&`b?4<a<>1<75f5783>>o2j3:17d;i:188k4>62900qo:>8;291?6=8r.:4l4ma:J733=O<?i0(nh52:k60?6=3`?=6=44i4`94?=n=o0;66a>8083>>{e<;i1<7;50;2x 4>f2kk0D999;I65g>"dn380e8:50;9j13<722c>n7>5;h7e>5<<g82:6=44}c61f?6==3:1<v*>8`8ae>N3??1C8;m4$bd96>o2<3:17d;9:188m0d=831b9k4?::m2<4<722wi8?o50;794?6|,82j6oo4H555?M21k2.hj7<4i4694?=n=?0;66g:b;29?l3a2900c<6>:188yg2513:197>50z&2<d<ei2B?;;5G47a8 f`=:2c>87>5;h75>5<<a<h1<75f5g83>>i6080;66sm43:94?3=83:p(<6n:cc8L1113A>=o6*lf;08m02=831b9;4?::k6f?6=3`?m6=44o0:2>5<<uk>9;7>55;294~"60h0im6F;779K03e<,jl1>6g:4;29?l312900e8l50;9j1c<722e:4<4?::a070=83?1<7>t$0:b>gg<@===7E:9c:&`b?4<a<>1<75f5783>>o2j3:17d;i:188k4>62900qo:=5;291?6=8r.:4l4ma:J733=O<?i0(nh52:k60?6=3`?=6=44i4`94?=n=o0;66a>8083>>{e<;>1<7;50;2x 4>f2kk0D999;I65g>"dn380e8:50;9j13<722c>n7>5;h7e>5<<g82:6=44}c617?6==3:1<v*>8`8ae>N3??1C8;m4$bd96>o2<3:17d;9:188m0d=831b9k4?::m2<4<722wi8>850;794?6|,82j6oo4H555?M21k2.hj7<4i4694?=n=?0;66g:b;29?l3a2900c<6>:188yg24=3:197>50z&2<d<ei2B?;;5G47a8 f`=:2c>87>5;h75>5<<a<h1<75f5g83>>i6080;66sm42694?3=83:p(<6n:cc8L1113A>=o6*lf;08m02=831b9;4?::k6f?6=3`?m6=44o0:2>5<<uk>8?7>55;294~"60h0im6F;779K03e<,jl1>6g:4;29?l312900e8l50;9j1c<722e:4<4?::a064=83?1<7>t$0:b>gg<@===7E:9c:&`b?4<a<>1<75f5783>>o2j3:17d;i:188k4>62900qo:<1;291?6=8r.:4l4ma:J733=O<?i0(nh52:k60?6=3`?=6=44i4`94?=n=o0;66a>8083>>{e<::1<7;50;2x 4>f2kk0D999;I65g>"dn380e8:50;9j13<722c>n7>5;h7e>5<<g82:6=44}c61b?6==3:1<v*>8`8ae>N3??1C8;m4$bd96>o2<3:17d;9:188m0d=831b9k4?::m2<4<722wi8>k50;794?6|,82j6oo4H555?M21k2.hj7<4i4694?=n=?0;66g:b;29?l3a2900c<6>:188yg24l3:197>50z&2<d<ei2B?;;5G47a8 f`=:2c>87>5;h75>5<<a<h1<75f5g83>>i6080;66sm42a94?3=83:p(<6n:cc8L1113A>=o6*lf;08m02=831b9;4?::k6f?6=3`?m6=44o0:2>5<<uk>8n7>55;294~"60h0im6F;779K03e<,jl1>6g:4;29?l312900e8l50;9j1c<722e:4<4?::a06g=83?1<7>t$0:b>gg<@===7E:9c:&`b?4<a<>1<75f5783>>o2j3:17d;i:188k4>62900qo:<9;291?6=8r.:4l4ma:J733=O<?i0(nh52:k60?6=3`?=6=44i4`94?=n=o0;66a>8083>>{e<:21<7;50;2x 4>f2kk0D999;I65g>"dn380e8:50;9j13<722c>n7>5;h7e>5<<g82:6=44}c603?6==3:1<v*>8`8ae>N3??1C8;m4$bd96>o2<3:17d;9:188m0d=831b9k4?::m2<4<722wi8?k50;794?6|,82j6oo4H555?M21k2.hj7<4i4694?=n=?0;66g:b;29?l3a2900c<6>:188yg25l3:197>50z&2<d<ei2B?;;5G47a8 f`=:2c>87>5;h75>5<<a<h1<75f5g83>>i6080;66sm47494?5=83:p(<6n:03:?M20>2B?:n5+cg817>od;3:17dm;:188k41f2900qo::b;297?6=8r.:4l4>189K020<@=<h7)mi:318mf5=831bo94?::m23d<722wi><h50;194?6|,82j6<?6;I642>N3>j1/ok4=5:k`7?6=3`i?6=44o05b>5<<uk;i>7>53;294~"60h0:=45G4648L10d3-im6?;4ib194?=nk=0;66a>7`83>>{e90i1<7=50;2x 4>f28;27E:86:J72f=#ko0996gl3;29?le32900c<9n:188yg7>j3:1?7>50z&2<d<6901C8:84H54`?!ea2;?0en=50;9jg1<722e:;l4?::a5<g=8391<7>t$0:b>47>3A><:6F;6b9'gc<5=2ch?7>5;ha7>5<<g8=j6=44}c3:=?6=;3:1<v*>8`825<=O<><0D98l;%ae>73<aj91<75fc583>>i6?h0;66sm18:94?5=83:p(<6n:03:?M20>2B?:n5+cg811>od;3:17dm;:188k41f2900qo?67;297?6=8r.:4l4>189K020<@=<h7)mi:378mf5=831bo94?::m23d<722wi=4850;194?6|,82j6<?6;I642>N3>j1/ok4=5:k`7?6=3`i?6=44o05b>5<<uk;297>53;294~"60h0:=45G4648L10d3-im6?;4ib194?=nk=0;66a>7`83>>{e90>1<7=50;2x 4>f28;27E:86:J72f=#ko0996gl3;29?le32900c<9n:188yg7>;3:1?7>50z&2<d<6901C8:84H54`?!ea2;?0en=50;9jg1<722e:;l4?::a5<4=8391<7>t$0:b>47>3A><:6F;6b9'gc<5=2ch?7>5;ha7>5<<g8=j6=44}c3:5?6=;3:1<v*>8`825<=O<><0D98l;%ae>73<aj91<75fc583>>i6?h0;66sm18294?5=83:p(<6n:03:?M20>2B?:n5+cg811>od;3:17dm;:188k41f2900qo?7f;297?6=8r.:4l4>189K020<@=<h7)mi:378mf5=831bo94?::m23d<722wi=5k50;194?6|,82j6<?6;I642>N3>j1/ok4=5:k`7?6=3`i?6=44o05b>5<<uk;3h7>53;294~"60h0:=45G4648L10d3-im6?;4ib194?=nk=0;66a>7`83>>{e91i1<7=50;2x 4>f28;27E:86:J72f=#ko0996gl3;29?le32900c<9n:188yg7?j3:1?7>50z&2<d<6901C8:84H54`?!ea2;?0en=50;9jg1<722e:;l4?::a677=83>1<7>t$0:b>47e3A><:6F;6b9'gc<4>2ch?7>5;ha7>5<<aj?1<75`16c94?=zj8h?6=4;:183!7?i3;:n6F;779K03e<,jl1?;5fc283>>od<3:17dm::188k41f2900qo<k1;290?6=8r.:4l4>1c9K020<@=<h7)mi:3f8mf5=831bo94?::k`1?6=3f;<m7>5;|`166<72<0;6=u+19c954c<@===7E:9c:&`b?4>3`i86=44ib694?=nk<0;66gl6;29?j70i3:17pl>b783>0<729q/=5o510g8L1113A>=o6*lf;0:?le42900en:50;9jg0<722ch:7>5;n34e?6=3th9h54?:483>5}#91k1=<k4H555?M21k2.hj7;:;ha0>5<<aj>1<75fc483>>od>3:17b?8a;29?xd5l=0;684?:1y'5=g=98o0D999;I65g>"dn38j7dm<:188mf2=831bo84?::k`2?6=3f;<m7>5;|`0g<<72:0;6=u+19c954?<@===7E:9c:&`b?443`i86=44ib694?=h9>k1<75rb3ag>5<3290;w)?7a;32f>N3??1C8;m4$bd962=nk:0;66gl4;29?le22900c<9n:188yg45=3:1?7>50z&2<d<6901C8:84H54`?!ea2;?0en=50;9jg1<722e:;l4?::a5g>=8391<7>t$0:b>47>3A><:6F;6b9'gc<5=2ch?7>5;ha7>5<<g8=j6=44}c013?6=<3:1<v*>8`825g=O<><0D98l;%ae>60<aj91<75fc583>>od=3:17b?8a;29?xd6jh0;694?:1y'5=g=98h0D999;I65g>"dn39=7dm<:188mf2=831bo84?::m23d<722wi>?750;794?6|,82j6<?j;I642>N3>j1/ok4=9:k`7?6=3`i?6=44ib794?=nk?0;66a>7`83>>{e9ki1<7;50;2x 4>f28;n7E:86:J72f=#ko0956gl3;29?le32900en;50;9jg3<722e:;l4?::a6fe=83?1<7>t$0:b>47b3A><:6F;6b9'gc<5<2ch?7>5;ha7>5<<aj?1<75fc783>>i6?h0;66sm44194?5=83:p(<6n:03:?M20>2B?:n5+cg8a6>od;3:17dm;:188k41f2900qo=8a;291?6=8r.:4l4>1d9K020<@=<h7)mi:278mf5=831bo94?::k`1?6=3`i=6=44o05b>5<<uk9=;7>55;294~"60h0:=h5G4648L10d3-im6>;4ib194?=nk=0;66gl5;29?le12900c<9n:188yg4an3:197>50z&2<d<69l1C8:84H54`?!ea2:?0en=50;9jg1<722ch97>5;ha5>5<<g8=j6=44}c0fg?6==3:1<v*>8`825`=O<><0D98l;%ae>63<aj91<75fc583>>od=3:17dm9:188k41f2900qo=89;291?6=8r.:4l4>1d9K020<@=<h7)mi:278mf5=831bo94?::k`1?6=3`i=6=44o05b>5<<uk9=:7>55;294~"60h0:=h5G4648L10d3-im6>;4ib194?=nk=0;66gl5;29?le12900c<9n:188yg4am3:197>50z&2<d<69l1C8:84H54`?!ea2:?0en=50;9jg1<722ch97>5;ha5>5<<g8=j6=44}c0ff?6==3:1<v*>8`825`=O<><0D98l;%ae>63<aj91<75fc583>>od=3:17dm9:188k41f2900qo<na;291?6=8r.:4l4>1d9K020<@=<h7)mi:338mf5=831bo94?::k`1?6=3`i=6=44o05b>5<<uk9<47>55;294~"60h0:=h5G4648L10d3-im6>;4ib194?=nk=0;66gl5;29?le12900c<9n:188yg51=3:197>50z&2<d<69l1C8:84H54`?!ea2:?0en=50;9jg1<722ch97>5;ha5>5<<g8=j6=44}c0e`?6==3:1<v*>8`825`=O<><0D98l;%ae>63<aj91<75fc583>>od=3:17dm9:188k41f2900qo<ja;291?6=8r.:4l4>1d9K020<@=<h7)mi:278mf5=831bo94?::k`1?6=3`i=6=44o05b>5<<uk9<;7>55;294~"60h0:=h5G4648L10d3-im6>;4ib194?=nk=0;66gl5;29?le12900c<9n:188yg51<3:197>50z&2<d<69l1C8:84H54`?!ea2:?0en=50;9jg1<722ch97>5;ha5>5<<g8=j6=44}c0eg?6==3:1<v*>8`825`=O<><0D98l;%ae>63<aj91<75fc583>>od=3:17dm9:188k41f2900qo<j9;291?6=8r.:4l4>1d9K020<@=<h7)mi:278mf5=831bo94?::k`1?6=3`i=6=44o05b>5<<uk9;87>54;294~"60h0:=o5G4648L10d3-im6o94ib194?=nk=0;66gl5;29?j70i3:17pl<8183>0<729q/=5o510g8L1113A>=o6*lf;72?le42900en:50;9jg0<722ch:7>5;n34e?6=3th8;;4?:483>5}#91k1=<k4H555?M21k2.hj7=:;ha0>5<<aj>1<75fc483>>od>3:17b?8a;29?xd4>:0;684?:1y'5=g=98o0D999;I65g>"dn39>7dm<:188mf2=831bo84?::k`2?6=3f;<m7>5;|`1bg<72<0;6=u+19c954c<@===7E:9c:&`b?523`i86=44ib694?=nk<0;66gl6;29?j70i3:17pl=e983>0<729q/=5o510g8L1113A>=o6*lf;16?le42900en:50;9jg0<722ch:7>5;n34e?6=3th9>n4?:283>5}#91k1=<74H555?M21k2.hj7=;;ha0>5<<aj>1<75`16c94?=zj8hm6=4<:183!7?i3;:56F;779K03e<,jl1?95fc283>>od<3:17b?8a;29?xd5:o0;694?:1y'5=g=98h0D999;I65g>"dn3837dm<:188mf2=831bo84?::m23d<722wi=n<50;694?6|,82j6<?m;I642>N3>j1/ok4=8:k`7?6=3`i?6=44ib794?=h9>k1<75rb312>5<2290;w)?7a;32a>N3??1C8;m4$bd972=nk:0;66gl4;29?le22900en850;9l52g=831vn?<m:186>5<7s-;3m7?>e:J733=O<?i0(nh5369jg6<722ch87>5;ha6>5<<aj<1<75`16c94?=zj8i?6=4::183!7?i3;:i6F;779K03e<,jl1?:5fc283>>od<3:17dm::188mf0=831d=:o50;9~f4db290>6=4?{%3;e?76m2B?;;5G47a8 f`=;>1bo>4?::k`0?6=3`i>6=44ib494?=h9>k1<75rb3cf>5<4290;w)?7a;32=>N3??1C8;m4$bd966=nk:0;66gl4;29?j70i3:17pl<8g83>6<729q/=5o510;8L1113A>=o6*lf;06?le42900en:50;9l52g=831vn?l?:187>5<7s-;3m7?>b:J733=O<?i0(nh51b9jg6<722ch87>5;ha6>5<<g8=j6=44}c1:4?6=<3:1<v*>8`825g=O<><0D98l;%ae>7d<aj91<75fc583>>od=3:17b?8a;29?xd5j;0;684?:1y'5=g=98o0D999;I65g>"dn38=7dm<:188mf2=831bo84?::k`2?6=3f;<m7>5;|`0=4<72<0;6=u+19c954c<@===7E:9c:&`b?4d3`i86=44ib694?=nk<0;66gl6;29?j70i3:17pl=b583>1<729q/=5o510`8L1113A>=o6*lf;10?le42900en:50;9jg0<722e:;l4?::a7f6=8391<7>t$0:b>47>3A><:6F;6b9'gc<5=2ch?7>5;ha7>5<<g8=j6=44}c1`6?6=<3:1<v*>8`825g=O<><0D98l;%ae>7d<aj91<75fc583>>od=3:17b?8a;29?xd4k=0;684?:1y'5=g=98o0D999;I65g>"dn38h7dm<:188mf2=831bo84?::k`2?6=3f;<m7>5;|`1f<<72<0;6=u+19c954c<@===7E:9c:&`b?073`i86=44ib694?=nk<0;66gl6;29?j70i3:17pl=bc83>0<729q/=5o510g8L1113A>=o6*lf;1:?le42900en:50;9jg0<722ch:7>5;n34e?6=3th9nl4?:483>5}#91k1=<k4H555?M21k2.hj7l<;ha0>5<<aj>1<75fc483>>od>3:17b?8a;29?xd5jj0;684?:1y'5=g=98o0D999;I65g>"dn3<;7dm<:188mf2=831bo84?::k`2?6=3f;<m7>5;|`1f`<72<0;6=u+19c954c<@===7E:9c:&`b?073`i86=44ib694?=nk<0;66gl6;29?j70i3:17pl=c883>1<729q/=5o510`8L1113A>=o6*lf;48mf5=831bo94?::k`1?6=3f;<m7>5;|`0<f<72<0;6=u+19c954c<@===7E:9c:&`b?553`i86=44ib694?=nk<0;66gl6;29?j70i3:17pl<2083>7<729q/=5o510:8L1113A>=o6*lf;3b?le42900c<9n:188yg56n3:1>7>50z&2<d<6911C8:84H54`?!ea28k0en=50;9l52g=831vn>?k:181>5<7s-;3m7?>8:J733=O<?i0(nh51`9jg6<722e:;l4?::a74d=8381<7>t$0:b>47?3A><:6F;6b9'gc<6i2ch?7>5;n34e?6=3th8=44?:383>5}#91k1=<64H555?M21k2.hj7?n;ha0>5<<g8=j6=44}c123?6=:3:1<v*>8`825==O<><0D98l;%ae>4g<aj91<75`16c94?=zj:;>6=4=:183!7?i3;:46F;779K03e<,jl1=l5fc283>>i6?h0;66sm30194?4=83:p(<6n:03;?M20>2B?:n5+cg82e>od;3:17b?8a;29?xd4980;6?4?:1y'5=g=9820D999;I65g>"dn3;j7dm<:188k41f2900qo=j5;296?6=8r.:4l4>199K020<@=<h7)mi:0c8mf5=831d=:o50;9~f6c429096=4?{%3;e?7602B?;;5G47a8 f`=9h1bo>4?::m23d<722wi?h?50;094?6|,82j6<?7;I642>N3>j1/ok4>a:k`7?6=3f;<m7>5;|`0`c<72;0;6=u+19c954><@===7E:9c:&`b?7f3`i86=44o05b>5<<uk9oh7>52;294~"60h0:=55G4648L10d3-im6<o4ib194?=h9>k1<75rb2fa>5<5290;w)?7a;32<>N3??1C8;m4$bd95d=nk:0;66a>7`83>>{e;m31<7<50;2x 4>f28;37E:86:J72f=#ko0:m6gl3;29?j70i3:17pl<d683>7<729q/=5o510:8L1113A>=o6*lf;3b?le42900c<9n:188yg5c=3:1>7>50z&2<d<6911C8:84H54`?!ea28k0en=50;9l52g=831vn><l:181>5<7s-;3m7?>8:J733=O<?i0(nh51`9jg6<722e:;l4?::a7c6=8381<7>t$0:b>47?3A><:6F;6b9'gc<6i2ch?7>5;n34e?6=3th9o>4?:483>5}#91k1=<k4H555?M21k2.hj7==;ha0>5<<aj>1<75fc483>>od>3:17b?8a;29?xd5jm0;684?:1y'5=g=98o0D999;I65g>"dn3hn7dm<:188mf2=831bo84?::k`2?6=3f;<m7>5;|`1ef<72<0;6=u+19c954c<@===7E:9c:&`b?553`i86=44ib694?=nk<0;66gl6;29?j70i3:17pl=b983>0<729q/=5o510g8L1113A>=o6*lf;0e?le42900en:50;9jg0<722ch:7>5;n34e?6=3th9ol4?:483>5}#91k1=<k4H555?M21k2.hj7==;ha0>5<<aj>1<75fc483>>od>3:17b?8a;29?xd5jo0;684?:1y'5=g=98o0D999;I65g>"dn3997dm<:188mf2=831bo84?::k`2?6=3f;<m7>5;|`1g=<72<0;6=u+19c954c<@===7E:9c:&`b?d33`i86=44ib694?=nk<0;66gl6;29?j70i3:17pl<8c83>6<729q/=5o510;8L1113A>=o6*lf;13?le42900en:50;9l52g=831vn>m9:186>5<7s-;3m7?>e:J733=O<?i0(nh52b9jg6<722ch87>5;ha6>5<<aj<1<75`16c94?=zj:i<6=4::183!7?i3;:i6F;779K03e<,jl1>n5fc283>>od<3:17dm::188mf0=831d=:o50;9~f7e1290>6=4?{%3;e?76m2B?;;5G47a8 f`=;11bo>4?::k`0?6=3`i>6=44ib494?=h9>k1<75rb3a3>5<2290;w)?7a;32a>N3??1C8;m4$bd96c=nk:0;66gl4;29?le22900en850;9l52g=831vn>6n:186>5<7s-;3m7?>e:J733=O<?i0(nh5339jg6<722ch87>5;ha6>5<<aj<1<75`16c94?=zj:2n6=4=:183!7?i3;:>6F;779K03e<aj81<75`16c94?=zj=?:6=494;294~"60h0:4?5G4648L10d3S?86lu6:`820?7228n1=h4>6;3e>41=:90v(<>j:59'55`=<2.h;7:4$b:90>"d13>0(no54:&`f?2<,ji186*>8780?!7??390(i>54:&g5?2<,m8186*k3;68 a2=<2.o97:4$e490>"c?3>0(i654:&g=?2<,mk186*kb;68 ae=<2.oh7:4$eg90>"cn3>0(h>54:&f5?2<,l8186*j3;68 `2=<2.n97:4$d490>"b?3>0(h654:&f=?2<,lk186*jb;68 `e=<2.nh7:4$dg90>"bn3>0(k>54:&e5?2<,o8186*i3;68 c2=<2.m97:4$g490>"a?3>0(k654:&e=?2<,ok186*ib;68 ce=<2.mh7:4$gg90>"an3>0(<>?:59'557=<2.:<?4;;%337?2<,8:?695+11790>"68?0?7)??7;68 46?2=1/==754:&24d<33-;;n7:4$02`>1=#99n186*;728734=#km0?7)?74;34=>"699087)?>1;18 1152==:7)mj:59j1<<722c>m7>5;h`6>5<<ak<1<75f19:94?=n9131<75f47d94?=n<>:1<75f4583>!70n3>87c?8e;28?l25290/=:h5429m52c=921b8<4?:%34b?243g;<i7<4;h63>5<#9>l18>5a16g97>=n;o0;6)?8f;60?k70m3>07d=j:18'52`=<:1e=:k55:9j7a<72-;<j7:<;o34a?0<3`9h6=4+16d906=i9>o1;65f3c83>!70n3>87c?8e;:8?l5f290/=:h5429m52c=121b8k4?:%34b?2b3g;<i7>4;h6g>5<#9>l18h5a16g95>=n<j0;6)?8f;6f?k70m3807d:m:18'52`=<l1e=:k53:9j0d<72-;<j7:j;o34a?2<3`>26=4+16d90`=i9>o1965f4983>!70n3>n7c?8e;48?l20290/=:h54d9m52c=?21b8;4?:%34b?2b3g;<i764;h66>5<#9>l18h5a16g9=>=n>00;6)?8f;4;?k70m3:07d88:18'52`=>11e=:k51:9j23<72-;<j787;o34a?4<3`<>6=4+16d92==i9>o1?65f6583>!70n3<37c?8e;68?l04290/=:h5699m52c==21b;?4?:%34b?0?3g;<i784;h52>5<#9>l1:55a16g93>=n?90;6)?8f;4;?k70m3207d8i:18'52`=>11e=:k59:9j2`<72-;<j787;o34a?g<3`<o6=4+16d92==i9>o1n65f6b83>!70n3<37c?8e;a8?l0e290/=:h5699m52c=l21b:l4?:%34b?0?3g;<i7k4;h41>5<#9>l1:55a16g9b>=n?h0;6)?8f;5:?k70m3:07d97:18'52`=?01e=:k51:9j32<72-;<j796;o34a?4<3`==6=4+16d93<=i9>o1?65f7483>!70n3=27c?8e;68?l13290/=:h5789m52c==21b4>4?:%34b?1>3g;<i784;h:1>5<#9>l1;45a16g93>=n080;6)?8f;5:?k70m3207d6?:18'52`=?01e=:k59:9j3c<72-;<j796;o34a?g<3`=n6=4+16d93<=i9>o1n65f7e83>!70n3=27c?8e;a8?l1d290/=:h5789m52c=l21b;o4?:%34b?1>3g;<i7k4;h50>5<#9>l1;45a16g9b>=n0?0;6)?8f;:6?k70m3:07d6;:18'52`=0<1e=:k51:9j<<<72-;<j767;o34a?6<3`2<6=4+16d9<==i9>o1=65`9083>!70n33;7c?8e;28?j>a290/=:h5919m52c=921d4h4?:%34b??73g;<i7<4;n:g>5<#9>l15=5a16g97>=h0j0;6)?8f;;3?k70m3>07b6m:18'52`=191e=:k55:9l=d<72-;<j77?;o34a?0<3f326=4+16d9=5=i9>o1;65`9983>!70n33;7c?8e;:8?j?0290/=:h5919m52c=121d5;4?:%34b??73g;<i7o4;n;6>5<#9>l15=5a16g9f>=h1=0;6)?8f;;3?k70m3i07b7<:18'52`=191e=:k5d:9l=7<72-;<j77?;o34a?c<3f2j6=4+16d9=5=i9>o1j65`ad83>!70n3ko7c?8e;28?jgd290/=:h5ae9m52c=921dm?4?:%34b?g63g;<i7>4;nc3>5<#9>l1m<5a16g95>=h1o0;6)?8f;c2?k70m3807b7j:18'52`=i81e=:k53:9l=a<72-;<j7o>;o34a?2<3f3h6=4+16d9e4=i9>o1965`ac83>!70n3k:7c?8e;48?jgf290/=:h5a09m52c=?21dm44?:%34b?g63g;<i764;nc;>5<#9>l1m<5a16g9=>=hi>0;6)?8f;c2?k70m3k07bo9:18'52`=i81e=:k5b:9le0<72-;<j7o>;o34a?e<3fk?6=4+16d9e4=i9>o1h65`a283>!70n3k:7c?8e;g8?j?e290/=:h5a09m52c=n21dn<4?:%34b?d73g;<i7>4;nce>5<#9>l1n=5a16g95>=zj;in6=4;:183!7?i3;:m6F;779K03e<,jl1>85fc283>>od<3:17b?>5;29?j70i3:17pl=b483>0<729q/=5o510a8L1113A>=o6*lf;0f?le42900en:50;9jg0<722e:=84?::m23d<722wi>nl50;794?6|,82j6<?l;I642>N3>j1/ok4<1:k`7?6=3`i?6=44ib794?=h98?1<75`16c94?=zj;h=6=49:183!7?i3;:j6F;779K03e<,jl1=o5fc283>>od<3:17dm::188mf0=831d=<;50;9l52g=831vn?m;:187>5<7s-;3m7?>d:J733=O<?i0(nh5309jg6<722ch87>5;ha6>5<<g8;>6=44}c0`1?6==3:1<v*>8`8265=O<><0D98l;%ae>64<aj91<75fc583>>od=3:17dm9:188k4722900qo=l8;291?6=8r.:4l4>1b9K020<@=<h7)mi:238mf5=831bo94?::k`1?6=3f;:97>5;n34e?6=3th9o<4?:483>5}#91k1=?>4H555?M21k2.hj7==;ha0>5<<aj>1<75fc483>>od>3:17b?>5;29?xd5k>0;6;4?:1y'5=g=98l0D999;I65g>"dn3?0en=50;9jg1<722ch97>5;ha5>5<<g8;>6=44o05b>5<<uz??>7>56z\607=::m;1o8522e:9g3=::m>1o;522bf9g0=::ji1o85rs5:f>5<1:rT?5=5Q46d8Z02f3W??46P;7d9]113<V=o>7S;;9:\7a3=Y=920R96:;_6;`>X30j1U85l4^5:b?[2?12T?455Q4958Z1>13W>386P;829>021=k9168;<55g9>001==o168;?55g9>036==o1688h55g9>03g==o168;755g9>6<c=91:01?7i:0:3?84f93;3<63=a382<5=::h91=5>4=3c7>4>7348j97?70:?1e3<60916>l95192897g?282;70<n0;3;4>;5m;0==63=e0855>;5m90==63=dg855>;5ll0==63=f4855>;5n=0==63=f2855>;5n;0==63=f0855>;4=m0==63<5b855>;4=k0==63<5`855>;4=00==63<71855>;4>o0==63<6d855>;4>m0==63<6b855>;4:90==63<1d855>;49j0==63<1`855>;4910==63<17855>;49=0==63<13855>;4990==63<e5855>;4m;0==63<e1855>;4ll0==63<db855>;4lh0==63<d9855>;4l?0==63<d5855>;3=80:45524439026<5=?:6:o4=572>2><5=?:6:94=572>20<5=?:6:;4=572>22<5=?:65=4=572>=4<5=?:65?4=572>=6<5=?:6:h4=572>2c<5=?:6:j4=572>2e<5=?:6:l4=572>25<5=?:6574=572>=1<uz??87>53z\601=:<?81=5>4=574>4>73ty?hn4?:3y]0ae<5;n=6<6>;|q626<72:qU9;=4=2a:>f2<5:2;6n;4}r71e?6=>>qU9?o4=57:>02<5=?368:4=574>02<5=<:68:4=543>02<5=?m68:4=221>02<5;3n68:4=3;e>02<5;k:68:4=3c1>02<5;k868:4=3c7>02<5;k>68:4=3c5>02<5;k<68:4=3c;>02<5;k;68:4=33g>02<5;;h68:4=33a>02<5;;j68:4=33:>02<5;;368:4=334>02<5;;=68:4=336>02<5;;?68:4=34g>02<5;<h68:4=34a>02<5;<j68:4=34:>02<5;<368:4=344>02<5;<=68:4=346>02<5;<?68:4=37:>02<5;?368:4=374>02<5;?=68:4=376>02<5;??68:4=370>02<5;?968:4=372>02<5;?;68:4=0f;>02<58n<68:4=0f5>02<58n>68:4=0f7>02<58n868:4=0f1>02<58n:68:4=0f3>02<58im68:4=263>02<5:9m68:4=21g>02<5:9h68:4=21f>02<5:9i68:4=21b>02<5:9368:4=214>02<5:9268:4=277>02<5:?868:4=271>02<5:?:68:4=273>02<5:>m68:4=26f>02<5:>o68:4=26`>02<5:>i68:4=3f1>02<5;im68:4=3f:>02<5;n=68:4=3f6>02<5=9=68:4=516>02<5=9?68:4=510>02<5=9968:4=512>02<5=9;68:4=50e>02<5=9n68:4=51g>02<5=9h68:4=51a>02<5=9j68:4=51:>02<5=9368:4=514>02<5=8n68:4=50g>02<5=?:68o4}r6f6?6=:rT?i?5236g95=7<uz??n7>55`y]11d<5=<?68:4=541>02<5=<868:4=54b>02<5=<268:4=25f>02<5:=o68:4=2`3>02<5:h:68:4=2`0>02<5:h?68:4=2`6>02<5:h=68:4=2`4>02<5:h368:4=2`:>02<5:hj68:4=2`1>02<58h;68:4=0ce>02<58kn68:4=0cg>02<58kh68:4=0ca>02<58kj68:4=0c:>02<58k368:4=0c4>02<5;:;68:4=0de>02<58ln68:4=0dg>02<58lh68:4=0da>02<58lj68:4=0d:>02<58l368:4=0d4>02<58oh68:4=0ga>02<58oj68:4=0g:>02<58o368:4=0g4>02<58o=68:4=0g6>02<58o?68:4=0g0>02<5;>>68:4=367>02<5;>868:4=361>02<5;>:68:4=363>02<5;9m68:4=31f>02<5;9o68:4=31`>02<5=:?68:4=520>02<5=::68:4=523>02<5=:968:4=2de>02<5:ln68:4=2d`>02<5:li68:4=2dg>02<5=;:68:4=52e>02<5=;;68:4=531>02<5=;868:4=535>02<5=;?68:4=536>02<5=;<68:4=53;>02<5=8h68:4=50a>02<5=8j68:4=50:>02<5=8368:4=504>02<5=8=68:4=506>02<5=8?68:4=500>02<5=?:6874}r76=?6=:rT>8h523c095=7<uz?=>7>52z\613=:;kk1=5?4}r755?6=:rT>98523c;95=7<uz?=<7>52z\611=:;k21=5?4}r76b?6=:rT>9>523c595=7<uz?>i7>52z\617=:;k<1=5?4}r76`?6=:rT>9<523c795=7<uz?>o7>52z\615=:;k>1=5?4}r76f?6=:rT>8k523c195=7<uz?>m7>52z\60a=:;k;1=5?4}r763?6=:rT>8n523c295=7<uz>o=7>52z\7fc=:<:<1=5?4}r6`b?6=:rT?nh5242795=7<uz>hi7>52z\7fa=:<:>1=5?4}r6``?6=:rT?nn5242195=7<uz>ho7>52z\7fg=:<:81=5?4}r6`f?6=:rT?nl5242395=7<uz>hm7>52z\7f<=:<::1=5?4}r6`=?6=:rT?n55243d95=7<uz>om7>52z\7g2=:<:o1=5?4}r6g=?6=:rT?o;5242f95=7<uz>o47>52z\7g0=:<:i1=5?4}r6g3?6=:rT?o95242`95=7<uz>o:7>52z\7g6=:<:k1=5?4}r6g1?6=:rT?o?5242;95=7<uz>o87>52z\7g4=:<:21=5?4}r6g7?6=:rT?o=5242595=7<uz>o>7>52z\7f2=:<;o1=5?4}r6`<?6=:rT?n;5243f95=7<uz?847>52z\66a=::h:1=5?4}r775?6=:rT>?8522`:95=7<uz??<7>52z\671=::h=1=5?4}r70b?6=:rT>?>522`495=7<uz?8i7>52z\677=::h?1=5?4}r70`?6=:rT>?<522`695=7<uz?8o7>52z\675=::h91=5?4}r70f?6=:rT>>k522`095=7<uz?8m7>52z\66`=::h;1=5?4}r70=?6=:rT>>n5228d95=7<uz?8:7>52z\66g=::0o1=5?4}r6bg?6=:rT?5l524439<3=z{=kj6=4={_6:=>;3=80=56s|4`;94?4|V=3370::1;44?xu3i10;6?uQ485891362?<0q~:n7;296~X31?1688?5649~w1g12909wS:65:?714<1<2wx8l;50;0xZ1?334>>=78<;|q7e1<72;qU84=4=572>24<uz>i97>52z\7e7=:<<;1;<5rs5`7>5<5sW>j=63;508;0>{t<k91<7<t^5c3?82293=;7p};b383>7}Y<0l019;>:7d8yv2e93:1>vP;9d9>007=>l1v9l?:181[2>l27?9<49d:p0d`=838pR97l;<665?0d3ty?mh4?:3y]0<d<5=?:6;l4}r6b`?6=:rT?5?5244392d=z{=k86=4={_6:5>;3=80=>6s|13794?c|5==36<9l;<0;4?3?3482?7;7;<1:6?3?349j97;7;<0ga?3?348m=7;7;<16=?3?349=o7;7;<116?3?349:<7;7;<1f2?3?349o87;7;<665?d23ty?954?:2y>00?==o168865193891302<<0q~::9;296~;3=00:4<5244`9g6=z{=<86=4<{<650?3a34>=>7;9;<657?7?92wx8;:50;0x9103282:70:96;a0?xu3=>0;6>u244:91c=:<<=1=5?4=57a>f2<uz>=>7>53z?727<608168;=55g9>030=k=1v9;n:18782193;3<63;6182<5=:<<l1=5>4=57a>41f3ty?9h4?:3;x9106282:70=?2;3;4>;51l0>n63=9g86f>;5i80>n63=a386f>;5i:0>n63=a586f>;5i<0>n63=a786f>;5i>0>n63=a986f>;5i90>n63<4186f>;4;o0>n63<3e86f>;4;j0>n63<3d86f>;4;k0>n63<3`86f>;4;10>n63<3682<5=:;:319o5234691g=:;<919o5234091g=:;<;19o5234291g=:;=l19o5235g91g=:;=n19o5235a91g=:;=h19o522e091g=::jl19o522e;91g=::m<1=5>4=3f6>4>7348jm7m;;<0a2?e3348h;7m<;|q71a<72;3p198?:0:2?846l3?i70<>c;7a?846j3?i70<>a;7a?84613?i70<>8;7a?846?3?i70<>6;7a?846=3?i70<>4;7a?841l3?i70<9c;7a?841j3?i70<9a;7a?84113?i70<98;7a?841?3?i70<96;7a?841=3?i70<94;7a?84213?i70<:8;7a?842?3?i70<:6;7a?842=3?i70<:4;7a?842;3?i70<:2;7a?84293?i70<:0;7a?87c03?i70?k7;7a?87c>3?i70?k5;7a?87c<3?i70?k3;7a?87c:3?i70?k1;7a?87c83?i70?lf;7a?xu3=j0;6<;t=57e>4>634>8:7;m;<601?3e34>887;m;<607?3e34>8>7;m;<605?3e34>8<7;m;<61b?3e34>8i7;m;<60`?3e34>8o7;m;<60f?3e34>8m7;m;<60=?3e34>847;m;<603?3e34>9i7;m;<61`?3e34>>?7m;;<665?7?12wx8;;50;1x910f282;70:99;3;4>;3>?0:;l5rs54;>5<5kr7?:l4>809>72c=91:01>9k:0:3?85e83?i70=m1;7a?85e;3?i70=m4;7a?85e=3?i70=m6;7a?85e?3?i70=m8;7a?85e13?i70=ma;7a?85e:3?i70:?4;7a?827;3?i70:?1;7a?82783?i70:?2;7a?85an3?i70=ie;7a?85ak3;3<63<fc86f>;4nm0>n63;1086f>;38o0:4=5240291g=:<8819o5240191g=:<8<19o5240691g=:<8?19o5240591g=:<8219o5243a91g=:<;h19o5243c91g=:<;319o5243:91g=:<;=19o5243491g=:<;?19o5243691g=:<;919o5rs544>5<51r7?:44>809>5g6==k16=lh55c9>5dc==k16=lj55c9>5de==k16=ll55c9>5dg==k16=l755c9>5d>==k16=l955c9>656==k16=kh55c9>5cc==k16=kj55c9>5ce==k16=kl55c9>5cg==k16=k755c9>5c>==k16=k955c9>5`e==k16=hl55c9>5`g==k16=h755c9>5`>==k16=h955c9>5`0==k16=h;55c9>5`2==k16=h=55c9>613==k16>9:55c9>615==k16>9<55c9>617==k16>9>55c9>66`==k16>>k55c9>66b==k16>>m55c9~w6642909w0=?2;7e?857<3;<m6s|31094?5|5::96<6>;<0g0?e4348ho7m<;|q1e<<72;q6>4k55g9>6dg=9>k0q~<nd;296~;51o0>j63=ad823d=z{;km6=4={<0b5?3a348i<7?8a:p6g7=838p1?o=:4d897d528=j7p}=b283>7}::h919k522c6952g<uz8i;7>52z?1e1<2n279n44>7`9~w7df2909w0<n5;7e?84ei3;<m6s|2ca94?4|5;k=68h4=3``>41f3ty9nh4?:3y>6d1==o16>ok516c8yv4d:3:1>v3=a986b>;5k10:;l5rs3ca>5<5s48j<7;i;<0bg?70i2wx?:h50;1x961b2<l01>9k:4d896>728=j7p}<7e83>6}:;>n1=5?4=2a:>f5<5:2;6n:4}r1bb?6=:r78n=4:f:?0e0<6?h1v>lm:18185e93?m70=7e;34e>{t;ki1<7<t=2`0>0`<5:2m6<9n;|q0fa<72;q6?o:55g9>7<6=9>k0q~=me;296~;4j<0>j63<90823d=z{:hm6=4={<1a2?3a349h<7?8a:p7f7=838p1>l8:4d896e528=j7p}<c283>7}:;k219k523b6952g<uz9h97>52z?0f<<2n278o;4>7`9~w6e02909w0=ma;7e?85d?3;<m6s|39c94?4|5:h968h4=2:b>41f3ty9<l4?:4y>6=?=k:16>5>5609>642=91;01?hm:b4897c?2j<0q~=;1;291~;5000h863<4c82<4=:9091o9522d:9g0=:<<;1885rs3::>5<4s48357?8a:?1<5<60:16>4=51068yv4?83:1?v3=81823d=::1;1955228691==z{;3o6=4={<0:7?70i279ml4l6:p65d=83?p1?6n:b1897>62?;01??::0:2?84aj3i?70<j8;a7?xu4<;0;6;u229c9g1=:;=i1=5?4=0;0>f5<58396n:4=3g;>f5<5=?:6984}r0;e?6=;r794l4>7`9>6=7=91901?7;:037?xu5080;6>u2293952g<5;296864=3;6>0><uz8<j7>58z?1=1<6?h16>lk5c29>6g6=k<16>o<5c79>6g>=k:16>o;5c29>6g0=k?16>n?5c29~w76d290>w0<7b;a0?84?:3<:70<>6;3;5>;5nj0h:63=e88`2>{t;=91<78t=3:a>f2<5:>o6<6>;<3:6?e434;2=7m;;<0f=?e234>>=7:8;|q1<g<72:q6>5l516c897>5282870<65;320>{t:181<7=t=3:1>41f3483?7;7;<0:2?3?3ty9;o4?:8y>6<3=9>k01?l?:b6897d52j901?m<:b7897d?2j>01?l::b6897e32j901?m::b1897e62j>0q~<?d;291~;50j0h?63=82855>;59>0:4<522ga9g1=::l31o95rs267>5<1s483o7m;;<17a?7?927:5<4l3:?2=5<d<279i44l3:?714<302wx>5m50;1x97>d28=j70<73;3;7>;51?0:=95rs3:0>5<4s483?7?8a:?1<1<202795:4:8:p62e=832p1?79:05b?84e:3i?70<l3;a7?84e03i>70<m5;a6?84d<3i?70<l5;a7?84d93i>7p}=0d83>0}::1n1o>52296924=::821=5?4=3dg>f0<5;oj6n84}r171?6=>r794i4l4:?00c<60816=4>5c29>5=`=k=16>ho5c49>007=<01v?6k:18084?l3;<m63=8582<6=::0=1=<:4}r0;0?6=;r79494>7`9>6=3==116>465599~w71c2902w0<67;34e>;5j=0h863=bc8`1>;5k:0h?63=be8`1>;5j10h:63=c58`1>;5k<0h963=c08`2>{t:9l1<7;t=3:f>f5<5;2>6;?4=33:>4>6348mh7m;;<0fe?e33ty88;4?:7y>6=c=k=16?8>5193894>a2j901<6j:b6897cf2j9019;>:5c8yv4?m3:1?v3=8d823d=::1?1=5=4=3;;>4733ty9484?:2y>6=3=9>k01?69:4:897?>2<20q~<8e;29=~;5110:;l522c;9g6=::kh1o9522cc9g1=::kn1o9522bc9g1=::j:1o8522b`9g0=::j?1o;5rs333>5<2s483j7m<;<0;2?06348:m7?71:?1b`<d>279io4l6:p711=83<p1?6i:b689636282:70?7e;a0?87?l3i?70<jb;a6?82293>i7p}=8g83>6}::1l1=:o4=3:5>4>4348257?>4:p6=0=839p1?69:05b?84??3?370<6a;7;?xu5?>0;6:u228;952g<5;hj6n=4=3`g>f5<5;ij6n=4=3`e>f2<5;i;6n:4=3aa>f2<uz8:=7>55z?1=5<d;2794:491:?15g<60816>kk5c59>6`d=k=1v>:7:18584>83i?70=:2;3;5>;60m0h?63>8b8`0>;5mk0h?63;5087g>{t:0:1<7=t=3;3>41f3483;7?73:?1=d<69=1v?68:18084??3;<m63=8986<>;51k0>46s|26:94?0|5;3j6<9n;<0ag?e4348h57m<;<0ab?e4348h<7m<;<0`f?e43ty9=?4?:4y>6<7=k:16>565609>64e=91;01?hi:b4897cd2j<0q~=;9;292~;5180h863<5282<4=:91i1o>5219`9g1=::li1o85244390a=z{;3:6=4<{<0:5?70i279454>829>6<d=98>0q~<78;296~;5010:;l5228a91==z{;=26=4:{<0:f?70i279nh4l3:?1g<<d<279mn4l3:?1g3<d<2wx><=50;6x97?52j901??k:0:2?84an3i?70<jc;a7?xu4<h0;6;u22809g1=:9m219k5234695=7<582i6n=4=3g`>f5<5=?:69h4}r0:6?6=:r795?4>7`9>6<e=98>0q~<8a;290~;51j0:;l522b;9g0=::hi1o9522b:9g6=z{=;26=4:{<1:f?e43492>78>;<617?7?927:5n4l4:?714<4i2wx=4j50;6x96?e2j>01<o8:0:2?850>3i=70=93;a5?xu41k0;6>u238`952g<5:396<6<;<1b1?76<2wx?4<50;1x96?528=j70=63;7;?85f>3?37p}>9d83>1}:;0i1o>521`:95=7<5:==6n:4=240>f2<uz>:m7>56z?0=f<d<2785>491:?761<60816=4m5c29>5<d=k=1688?53c9~w6?d2908w0=6c;34e>;41:0:4>523`49542<uz92?7>53z?0=6<6?h16?4:5599>7d1==11v>66:18585f>3;<m63<8g8`0>;4190h963<908`2>;40j0h?63<8d8`6>{t90l1<7:t=2;g>f5<58k26<6>;<143?e1349=87m9;|q75g<72?q6?4j5c59>7<2=>8168?;5193894?e2j901<7n:b6891362:i0q~=6d;297~;41m0:;l5238695=5<5:k<6<?;;|q0=1<72:q6?4:516c896?22<201>o7:4:8yv5?=3:19v3<a6823d=:;1l1o>523829g6=:;0;1o>5239a9g1=z{8k;6=4;{<1:a?e434;jm7?71:?032<d<278:94l4:p04e=83<p1>7j:b6896?22?;019<9:0:2?87>i3i870?69;a7?822939o7p}<9d83>6}:;0o1=:o4=2;6>4>4349j47?>4:p7<3=839p1>7::05b?85>>3?370=n9;7;?xu40?0;69u23`:952g<5:3;6n:4=2;2>f3<5:2h6n;4}r3b5?6=<r785k4l3:?2eg<60816?:65c79>733=k?1v9?k:18585>n3i?70=66;42?825?3;3=63>988`7>;6110h863;5080a>{t;0l1<7=t=2;e>41f3492:7?73:?0e<<69=1v>79:18085>>3;<m63<9686<>;4ih0>46s|39594?5|5:k26<9n;<1:5?e33493o7m9;|q75`<72?q6?l>5c29>7<1=>8168?65193894??2j901<78:b6891362:l0q~?n2;290~;4i90h863>ab82<4=:;>21o9523779g1=z{:k;6=4<{<1b4?70i2785:4>829>7dg=98>0q~=67;297~;41>0:;l5238:91==:;hh1955rs2:;>5<1s49jm7?8a:?0g5<d;278o?4l3:?0g1<d;2784o4l3:?0g=<d;2wx8<h50;4x96g62j901>77:738914>282:70?67;a0?87>>3i?70::1;63?xu6i:0;69u23`39g1=:9hn1=5?4=25:>f0<5:<=6n84}r1b5?6=;r78m<4>7`9>7<>=91901>om:037?xu4110;6>u238:952g<5:326864=2c`>0><uz93=7>55z?0eg<6?h16?n<5c59>7f2=k<16?5l5c59>7f>=k=1v9<?:18585f:3i870=69;42?825i3;3=63>978`7>;61<0h863;50875>{t9h>1<7:t=2c1>f2<58kn6<6>;<14=?e3349=:7m;;|q0e7<72:q6?l<516c896?>282870=nc;320>{t;031<7=t=2;:>41f3492m7;7;<1b`?3?3ty84?4?:5y>7de=9>k01>m;:b6896e12j901>m7:b78yv2593:1:v3<a28`7>;41h0==63;2c82<4=:90?1o>521869g1=:<<;18?5rs0c6>5<3s49j?7m;;<3bb?7?9278;l4l6:?022<d>2wx?l=50;1x96g428=j70=6a;3;7>;4im0:=95rs2;b>5<5s492m7?8a:?0e`<202wx?5=50;6x96gc28=j70=l6;a7?85d?3i870=7a;a0?xu3:;0;68u23`69g6=::=?19k5243a95=7<583?6n=4=572>12<uz;j:7>54z?0e1<d<27:n=4>809>72g=k=16?;95c59~w6g32909w0=n4;34e>;4il0:=95rs2:7>5<4s49ji7?8a:?0g2<d<2784l4l4:p6ab=838p1?k=:4:897c628=j7p}=e683>7}::l81=5=4=3g`>41f3ty8<=4?:3y>6`4=9>k01>>;:b78yv4ck3:1>v3=e086<>;5m90:;l5rs3g5>5<5s48n=7?73:?1ag<6?h1v?jm:18184b83?370<kf;34e>{t:l?1<7<t=3g3>4>4348nm7?8a:p6ag=838p1?ji:4:897bb28=j7p}=e583>7}::ml1=5=4=3g:>41f3ty9i>4?:3y>6ac=91901?k7:05b?xu5n90;6?u22g791==::o>1=:o4}r0ee?6=:r79j84>829>6c`=9>k0q~=?1;296~;5n<0:;l523169g6=z{;om6=4={<0e0?3?348m?7?8a:p6c?=838p1?h;:0:0?84am3;<m6s|2dg94?4|5;l86864=3d1>41f3ty9j54?:3y>6c5=91901?hk:05b?xu5mm0;6?u22g091==::o;1=:o4}r0e3?6=:r79j?4>829>6ce=9>k0q~<i6;296~;5n80:4>522g`952g<uz9>47>52z?01a<202789n4>7`9~w6052909w0=:d;3;7>;4>>0:;l5rs25a>5<5s49>h7?8a:?0<5<d;2wx?8950;0x963d2<201>;m:05b?xu4>80;6?u234a95=5<5:<=6<9n;|q013<72;q6?8l5599>70g=9>k0q~=90;296~;4=k0:4>52377952g<uz9>97>52z?01d<20278944>7`9~w63a2909w0=:a;3;7>;4>=0:;l5rs27f>5<5s49>57?73:?026<6?h1v>8m:18185083?370=9f;34e>{t;>?1<7<t=253>4>4349<m7?8a:p72e=838p1>9?:05b?85?83i=7p}<6`83>7}:;?l1955237g952g<uz9<87>52z?02c<60:16?:7516c8yv5113:1>v3<6d86<>;4>m0:;l5rs250>5<5s49=i7?73:?03=<6?h1v>87:181851l3?370=9c;34e>{t;>81<7<t=24g>4>4349<;7?8a:p727=838p1>8l:0:0?850>3;<m6s|1g494?3|58h;68h4=323>4>634;i>7m;;<3a0?e434;i:7m:;|q2f4<72;q6=lh55g9>5g4=9>k0q~?m3;296~;6il0>j63>b5823d=z{8h>6=49{<3b`?3a34;i:7?8a:?2f=<d<27:nl4l3:?2ff<d=27:nh4l6:p5g1=838p1<ol:4d894d?28=j7p}>b883>7}:9hh19k521cc952g<uz;in7>52z?2ed<2n27:nn4>7`9~w4dc2909w0?n9;7e?87en3;<m6s|1b394?4|58k368h4=0a1>41f3ty:o>4?:3y>5d1==o16=n:516c8yv41;3:19v3=1e86b>;5>m0:4<5220d9g1=::;;1o>522319g0=z{;;n6=4={<02g?3a348:j7?8a:p676=838p1??m:4d8974628=j7p}=2383>3}::8k19k52231952g<5;8>6n:4=304>f5<5;826n;4=30a>f0<uz8987>52z?15<<2n279>84>7`9~w7412909w0<>8;7e?845?3;<m6s|23:94?4|5;;<68h4=30:>41f3ty9>l4?:3y>640==o16>?m516c8yv45m3:1>v3=1486b>;5:o0:;l5rs313>5<5s48:87;i;<005?70i2wx>9h50;0x970c2<l01?;6:0:2?xu5<l0;6?u227a91c=::<21=5?4}r056?6=<r79:n4>809>64`=k:16>??5c59>675=k?1v?:k:181841j3?m70<:7;3;5>{t:?;1<7=t=34a>4>63489=7m:;<017?e43ty98n4?:3y>63g==o16>8851938yv4183:1>v3=6`82<4=::;91o95rs36a>5<5s48=57;i;<061?7?92wx>8h50;7x970>282:70<=5;a0?845?3i?70<=9;a5?845j3i>7p}=4`83>7}::?219k5224695=7<uz8>i7>54z?12=<60816>?95c49>67?=k:16>?l5c59~w72>2909w0<97;7e?842;3;3=6s|24f94?5|5;<<6<6>;<01=?e33489n7m<;|q10=<72;q6>;855g9>604=91;0q~<:c;290~;5>?0:4<5223a9g6=::;l1o9522239g0=z{;><6=4={<051?3a348>=7?71:p60d=839p1?8::0:2?845n3i870<<1;a7?xu5<?0;6?u227691c=::<:1=5?4}r06e?6=:r79:94>809>667=k:1v<k=:18184783?m70?jc;3;5>{t9l;1<7<t=0de>0`<58oi6<6>;|q2b0<72=q6=kh5193894d52j901<l;:b6894d12j<0q~?j0;296~;6nl0>j63>e`82<4=z{8l?6=4<{<3ea?7?927:n94l5:?2f3<d;2wx=ih50;0x94`c2<l01<k6:0:2?xu6n:0;6?u21gf95=7<58h=6n:4}r3ga?6=:r7:jn4:f:?2a=<6081v<h=:18687ak3;3=63>b98`7>;6jh0h863>bb8`2>;6jl0h96s|1ef94?4|58li68h4=0g4>4>63ty:j<4?:5y>5cd=91;01<ln:b7894dd2j901<lj:b68yv7ck3:1>v3>f`86b>;6m?0:4<5rs0d3>5<4s4;mm7?71:?2ff<d<27:nh4l3:p5ad=838p1<h6:4d894c2282:7p}>eg83>1}:9o31=5?4=0`e>f5<58i96n:4=0a7>f3<uz;om7>52z?2b=<2n27:i94>809~w4cb2908w0?i8;3;5>;6k;0h?63>c58`0>{t9m31<7<t=0d4>0`<58o86<6>;|q2aa<72;q6=k95193894e32j90q~<<b;296~;5=00>j63=4482<4=z{;9j6=4={<06<?3a348?87?71:p66?=838p1?;8:4d89724282:7p}=3983>7}::<<19k5225095=7<uz88;7>52z?110<2n2798<4>809~w7512909w0<:4;7e?84383;3=6s|22794?4|5;?868h4=31e>4>63ty9?94?:3y>604==o16>>k51938yv44;3:1>v3=5086b>;5;m0:4<5rs311>5<5s48><7;i;<00g?7?92wx=nk50;0x94cd2<l01<j7:0:2?xu6km0;6?u21d`91c=:9m=1=5?4}r3`g?6=:r7:il4:f:?2`3<6081v<mm:18187b13?m70?k5;3;5>{t9jk1<7<t=0g;>0`<58n?6<6>;|q2g<<72;q6=h955g9>5a5=91;0q~?l8;296~;6m?0>j63>d382<4=z{8i<6=4={<3f1?3a34;o=7?71:p5f0=838p1<k;:4d894b7282:7p}>c483>7}:9l919k521bd95=7<uz8;=7>52z?2`2<2n27:4o4>7`9~w7652909w0?k6;7e?87?k3;<m6s|21194?4|58n>68h4=0:g>41f3ty9<94?:3y>5a2==o16=5k516c8yv47=3:1>v3>d286b>;60o0:;l5rs325>5<5s4;o>7;i;<3:4?70i2wx>=950;0x94b62<l01<7>:05b?xu5810;6?u21e291c=:9081=:o4}r03=?6=:r7:ok4:f:?2=6<6?h1v?8j:181843<3?m70?64;34e>{t:?l1<7<t=360>0`<583>6<9n;|q135<72;q6>9<55g9>5<0=9>k0q~<81;296~;5<80>j63>96823d=z{;=96=4={<074?3a34;247?8a:p625=838p1?=i:4d894?>28=j7p}=7583>7}:::o19k5218c952g<uz8<97>52z?17a<2n27:5o4>7`9~w7112909w0<<c;7e?87>k3;<m6s|44694?70s49?<7;9;<10b?313498h7;9;<10g?313498i7;9;<10f?313498m7;9;<10<?313498;7;9;<10=?31349>87;9;<167?31349>>7;9;<165?31349><7;9;<17b?31349?i7;9;<17`?31349?o7;9;<17f?31348ho7?8a:?716<d;278<94l4:p75`=838p1>:?:4d8964e28=j7p}<3783>1}:;=:1=5?4=277>0`<5;lm6n=4=20`>f5<uz9;i7>52z?07c<2n278>l4>7`9~w652290?w0=<f;3;5>;4=:0>j63=fg8`1>;4:80h?6s|31a94?4|5:9o68h4=20;>41f3ty8?>4?:5y>76b=91;01>;>:4d897`b2j?01>?k:b18yv57j3:1>v3<3b86b>;4:>0:;l5rs211>5<3s498o7?71:?015<2n279ji4l3:?05g<d;2wx?=j50;0x965b2<l01><6:05b?xu4;=0;69u232g95=7<5:?968h4=3df>f5<5:;m6n=4}r13e?6=:r78?o4:f:?063<6?h1v>=>:187854j3;3=63<4g86b>;5nm0h963<188`7>{t;931<7<t=21b>0`<5:8>6<9n;|q075<72=q6?>o51938962b2<l01?hl:b1896702j90q~=?7;296~;4;10>j63<22823d=z{:8n6=4;{<10<?7?92788n4:f:?1bg<d;278=>4l3:p750=838p1>=8:4d8964528=j7p}<2e83>1}:;:=1=5?4=26a>0`<5;li6n;4=232>f5<uz9;47>52z?07<<2n278>94>7`9~w64a290?w0=<9;3;5>;4<m0>j63=fb8`1>;49<0h?6s|33294?4|5:8i6864=203>41f3ty8>n4?:3y>77d=98>01><l:05b?xu49l0;6>u233c91==:;;:1955230g952g<uz99=7>53z?06d<69=16??>51918964628=j7p}<1b83>6}:;;31955230g91==:;8i1=:o4}r12b?6=;r78>44>159>74c=91901>?i:05b?xu49h0;6>u233:91==:;8i1955230c952g<uz9:h7>53z?06=<69=16?<m51918967c28=j7p}<1983>6}:;;=1955230c91==:;821=:o4}r12f?6=;r78>:4>159>74g=91901>?m:05b?xu49?0;6>u233491==:;8219552304952g<uz9:57>53z?063<69=16?<651918967>28=j7p}<1583>6}:;;?1955230491==:;8>1=:o4}r123?6=;r78>84>159>740=91901>?8:05b?xu49;0;6>u233691==:;8>19552300952g<uz9:97>53z?061<69=16?<:51918967228=j7p}<1183>6}:;;91955230091==:;8:1=:o4}r127?6=;r78>>4>159>744=91901>?<:05b?xu4980;6>u23309542<5:;;6<6<;<125?70i2wx>i=50;0x97b52<l01?j;:05b?xu5l;0;65u22e095=7<5;n:6n:4=3f;>f3<5;n?6n;4=3ag>f5<5;ih6n:4=3af>f2<5;i<6n84}r0g4?6=;r79ok4:f:?1`<<2n279h<4>7`9~w7ea2903w0<lf;3;5>;5l80h?63=d98`0>;5l=0h863=ce8`0>;5kj0h:63=cd8`7>;5k>0h96s|2e;94?2|5;n26<6>;<0be?e2348i:7m<;<0`3?e33ty9h:4?:2y>6a0==o16>i;55g9>6a>=9>k0q~<k5;296~;5l<0:4<522e:9g6=z{=?=6=4=0z?741<2>27?<>4:6:?744<2>27?<=4:6:?747<2>278jk4:6:?0b`<2>278jn4:6:?0bg<2>278ji4:6:?754<2>27?<k4:6:?755<2>27?=?4:6:?756<2>27?=;4:6:?751<2>27?=84:6:?752<2>27?=54:6:?76f<2>27?>o4:6:?76d<2>27?>44:6:?76=<2>27?>:4:6:?763<2>27?>84:6:?761<2>27?>>4:6:?0g<<6?h1688?547d8yv5c;3:1>v3;0586b>;4mo0:;l5rs2db>5<3s4>;87?71:?75=<2n278;l4l3:?0b5<d;2wx?i<50;0x91642<l01>kj:05b?xu4n00;69u241195=7<5=;<68h4=25b>f3<5:o>6n=4}r1g4?6=:r7?<<4:f:?0af<6?h1v>h8:18782793;3=63;1486b>;4?00h963<e08`7>{t;jl1<7<t=523>0`<5:oi6<9n;|q0b3<72=q68=>5193891732<l01>97:b1896ba2j90q~=k1;296~;38;0>j63<ee823d=z{:l36=4;{<636?7?927?=;4:f:?03<<d;278i>4l3:p7fc=838p1>hi:4d896cf28=j7p}<f483>1}:;ol1=5?4=530>0`<5:=36n;4=2fg>f5<uz9hh7>52z?0b`<2n278i44>7`9~w6`3290?w0=ie;3;5>;39;0>j63<768`7>;4lk0h?6s|3b`94?4|5:lh68h4=2g4>41f3ty8j?4?:5y>7ce=91;019??:4d896112j901>j8:b18yv5di3:1>v3<fc86b>;4m?0:;l5rs2d2>5<3s49mn7?71:?74c<2n278;;4l5:?0`0<d;2wx?nm50;0x96`c2<l01>k7:05b?xu4n:0;69u23gf95=7<5=;:68h4=254>f3<5:n26n=4}r1f0?6=:r78ik4:8:?0a1<6?h1v>h?:18185bn3;:863<f1823d=z{:o96=4<{<1fa?3?349n87;7;<1f6?70i2wx?h;50;1x96cb28;?70=j4;3;7>;4m<0:;l5rs2g3>5<4s49nh7;7;<1f6?3?349n<7?8a:p7`5=839p1>kk:037?85b:3;3?63<e2823d=z{:nn6=4<{<1fg?3?349n<7;7;<1ga?70i2wx?h?50;1x96cd28;?70=j0;3;7>;4m80:;l5rs2f`>5<4s49nn7;7;<1ga?3?349oo7?8a:p7a`=839p1>km:037?85cm3;3?63<dg823d=z{:nj6=4<{<1fe?3?349oo7;7;<1ge?70i2wx?ij50;1x96cf28;?70=kc;3;7>;4lm0:;l5rs2f;>5<4s49n57;7;<1ge?3?349o47?8a:p7ad=839p1>k6:037?85ci3;3?63<dc823d=z{:n=6=4<{<1f<?3?349o47;7;<1g2?70i2wx?i750;1x96c?28;?70=k8;3;7>;4l00:;l5rs2f7>5<4s49n;7;7;<1g2?3?349o87?8a:p7a1=839p1>k8:037?85c>3;3?63<d6823d=z{:n>6=4<{<1f2?76<278h94>829>7a3=9>k0q~:?7;297~;3980:4<5243791c=:;?>1o85rs526>5<4s4>;j7?71:?766<2n278:>4l5:p050=839p19??:0:2?825<3?m70=93;a0?xu3810;6>u240095=7<5=8=68h4=247>f5<uz>;57>53z?756<608168?955g9>733=k<1v9>l:180826>3;3=63;2`86b>;4>?0h?6s|41c94?5|5=;?6<6>;<61<?3a349=97m<;|q74g<72:q68<;51938914>2<l01>89:b78yv27l3:1?v3;1682<4=:<;h19k523759g0=z{=:n6=4<{<62<?7?927?>n4:f:?022<d;2wx88;50;30824>3?=70:<5;75?824<3?=70:<3;75?824:3?=70:<1;75?82483?=70:=f;75?824m3?=70:<d;75?824k3?=70:<b;75?824i3?=70:<9;75?82403?=70:<7;75?825m3?=70:=d;75?84dl3;<m6s|45594?4|5=9=68h4=572>g7<uz>?:7>52z?770<2n27?9<4n2:p013=838p19=;:4d891362h:0q~:;4;296~;3;:0>j63;508:b>{t<=91<7<t=511>0`<5=?:64k4}r676?6=:r7??<4:f:?714<>l2wx89?50;0x91572<l019;>:8a8yv2383:1>v3;2g86b>;3=80jn6s|44294?4|5=9n68h4=572>dg<uz>?j7>52z?77a<2n27?9<4nf:p01c=838p19=l:4d891362h30q~:;d;296~;3;k0>j63;508b<>{t<=i1<7<t=51b>0`<5=?:6l94}r67f?6=:r7??44:f:?714<f>2wx89o50;0x915?2<l019;>:`78yv2313:1>v3;3686b>;3=80j86s|45:94?4|5=8n68h4=572>d5<uz>8j7>52z?76a<2n27?9<46b:p004=838p19;<:05b?82293h=7p}>6483>7}::hk1o>522bg9543<uz89h7>54z?16f<d<279>k4l5:?174<d>279>o4>7`9~w4e7290?w0?mf;a7?87d:3i>70?l4;a5?87em3;<m6s|17194??|5;kn6n:4=3`3>f5<5;h96n;4=3`7>f5<5;h26n;4=3``>f2<5;hn6n:4=3a5>f5<5;i<6<9n;|q22=<72:q6>o:5c49>6gd=k?16>o;516c8yv5?l3:1;v3<c18`0>;4k;0h963<c58`2>;40j0:;l523b49g0=:;j=1o85239c9g0=z{8<i6=4<{<0a=?e3348i47?8a:?1g3<d=2wx=;?50;6x97d>2j<01?ln:b7897e428=j70<nc;a5?xu6>j0;6?u22c`9g6=::j=1=<;4}r36e?6=:r79no4>7`9>6gg=k?1v<8k:18184ek3i>70<md;34e>{t9?>1<7=t=3``>f0<5;ij6<9n;<0`<?e23ty::k4?:3y>6gc=k<16>n>516c8yv71m3:1>v3=bd8`2>;5jo0:;l5rs3a:>5<5s48h57?8a:?1g=<d<2wx=;750;0x97e42j<01?l9:036?xu6>?0;6?u22cf9g3=::k?1=<;4}r30a?6=:r79mn4l5:?1gg<6?h1v<<l:18084di3i>70<mf;a6?84e>3;<m6s|14594?4|5;ij6n84=3a7>4723ty:944?:3y>6g`=k?16>n;51078yv72k3:1>v3=c98`2>;5k?0:;l5rs07e>5<5s493n7?8a:?0g3<d>2wx=;>50;0x96e02j<01>m7:05b?xu6>>0;6?u22b49g3=::jh1=<;4}r356?6=:r79o=4l6:?1g4<69<1v<8n:18185?i3i=70=l8;321>{t;9?1<7<t=3af>41f348i:7m:;|p0de=838pR97n;<71>1?f3->=n7?9e:p0dg=838pR976;<71>1?>3->=n7?9f:p0d?=838pR977;<71>1??3->=n7?80:p0d>=838pR978;<71>1?03->=n7?85:p0d1=838pR979;<71>1?13->=n7?=6:p0d0=838pR97:;<71>1?23->=n7?=c:p0d3=838pR97;;<71>1?33->=n7?<7:p0d2=838pR97<;<71>1?43->=n7?<e:p0g3=838pR9o=;<71>1g53->=n7?;9:p0g2=838pR9o>;<71>1g63->=n7?:2:p0g5=838pR9o?;<71>1g73->=n7?:6:p0g4=838pR97i;<71>1?a3->=n7?:7:p0g7=838pR97j;<71>1?b3->=n7?:8:p0g6=838pR97k;<71>1?c3->=n7?:9:p0d`=838pR97l;<71>1?d3->=n7?:b:p0dc=838pR97m;<71>1?e3->=n7?:c:p0db=838pR97=;<71>1?53->=n7?:d:p0d5=838pR97>;<71>1?63->=n7?:e:p17g=838pR8<n;<71>04f3->=n7?81:p114=838pR8:=;<71>0253->=n7?82:p112=838pR8:;;<71>0233->=n7?83:p11d=838pR8:m;<71>02e3->=n7?84:p135=838pR88<;<71>0043->=n7?86:p0a7=838pR9li;<71>1da3->=n7?=7:p0f`=838pR9lj;<71>1db3->=n7?=8:p0fc=838pR9lk;<71>1dc3->=n7?=9:p0fb=838pR9ll;<71>1dd3->=n7?=a:p0fe=838pR9lm;<71>1de3->=n7?=b:p0fd=838pR9ln;<71>1df3->=n7?=d:p0fg=838pR9l6;<71>1d>3->=n7?=e:p0f?=838pR9l7;<71>1d?3->=n7?=f:p0ag=838pR9m8;<71>1e03->=n7?<0:p0a?=838pR9m9;<71>1e13->=n7?<1:p0a>=838pR9m:;<71>1e23->=n7?<2:p0a1=838pR9m;;<71>1e33->=n7?<3:p0a0=838pR9m<;<71>1e43->=n7?<4:p0a3=838pR9m=;<71>1e53->=n7?<5:p0a2=838pR9m>;<71>1e63->=n7?<6:p0a5=838pR9m?;<71>1e73->=n7?<8:p0a4=838pR9l8;<71>1d03->=n7?<9:p0f>=838pR9l9;<71>1d13->=n7?<a:p0ae=838pR9jl;<71>1bd3->=n7?<b:p0`4=838pR9k=;<71>1c53->=n7?<c:p16>=838pR8<k;<71>04c3->=n7?<d:p117=838pR8=:;<71>0523->=n7?<f:p116=838pR8=;;<71>0533->=n7?;0:p16`=838pR8=<;<71>0543->=n7?;1:p16c=838pR8==;<71>0553->=n7?;2:p16b=838pR8=>;<71>0563->=n7?;3:p16e=838pR8=?;<71>0573->=n7?;4:p16d=838pR8<i;<71>04a3->=n7?;5:p16g=838pR8<j;<71>04b3->=n7?;6:p16?=838pR8<l;<71>04d3->=n7?;7:p160=838pR8<m;<71>04e3->=n7?;8:p10?=838pR8:j;<71>02b3->=n7?;a:p134=838pR8;9;<71>0313->=n7?;b:p137=838pR8;:;<71>0323->=n7?;c:p136=838pR8;;;<71>0333->=n7?;d:p10`=838pR8;<;<71>0343->=n7?;e:p10c=838pR8;=;<71>0353->=n7?;f:p10b=838pR8;>;<71>0363->=n7?:0:p10e=838pR8;?;<71>0373->=n7?:1:p10d=838pR8:i;<71>02a3->=n7?:3:p10g=838pR8:k;<71>02c3->=n7?:4:p101=838pR8:l;<71>02d3->=n7?:5:~jgdd2909wE:9c:mfgb=838pD98l;|laf`<72;qC8;m4}o`ab?6=:rB?:n5rnca3>5<5sA>=o6sabb394?4|@=<h7p`mc383>7}O<?i0qcll3;296~N3>j1vbom;:181M21k2wenn;50;0xL10d3tdio;4?:3yK03e<ughh;7>52zJ72f=zfki36=4={I65g>{ijj31<7<tH54`?xhekh0;6?uG47a8ykddj3:1>vF;6b9~jged2909wE:9c:mffb=838pD98l;|lag`<72;qC8;m4}o``b?6=:rB?:n5rncf3>5<5sA>=o6sabe394?4|@=<h7p`md383>7}O<?i0qclk3;296~N3>j1vboj;:181M21k2weni;50;0xL10d3tdih;4?:3yK03e<ugho;7>52zJ72f=zfkn36=4={I65g>{ijm31<7<tH54`?xhelh0;6?uG47a8ykdcj3:1>vF;6b9~jgbd2909wE:9c:mfab=838pD98l;|la``<72;qC8;m4}o`gb?6=:rB?:n5rncg3>5<5sA>=o6sabd394?4|@=<h7p`me383>7}O<?i0qclj3;296~N3>j1vbok;:181M21k2wenh;50;0xL10d3tdii;4?:3yK03e<ughn;7>52zJ72f=zfko36=4={I65g>{ijl31<7<tH54`?xhemh0;6?uG47a8ykdbj3:1>vF;6b9~jgcd2909wE:9c:mf`b=838pD98l;|laa`<72;qC8;m4}o`fb?6=:rB?:n5rncd3>5<5sA>=o6sabg394?4|@=<h7p`mf383>7}O<?i0qcli3;296~N3>j1vboh;:181M21k2wenk;50;0xL10d3tdij;4?:3yK03e<ughm;7>52zJ72f=zfkl36=4={I65g>{ijo31<7<tH54`?xhenh0;6?uG47a8ykdaj3:1>vF;6b9~jg`d2909wE:9c:m=a?=83;pD98l;|lb5d<728qC8;m4}oc2f?6=9rB?:n5rn`3`>5<6sA>=o6saa0f94?7|@=<h7p`n1d83>4}O<?i0qco>f;295~N3>j1vbl<?:182M21k2wem??50;3xL10d3tdj>?4?:0yK03e<ugk9?7>51zJ72f=zfh8?6=4>{I65g>{ii;?1<7?tH54`?xhf:?0;6<uG47a8ykg5?3:1=vF;6b9~jd4?290:wE:9c:me7?=83;pD98l;|lb6d<728qC8;m4}oc1f?6=9rB?:n5rn`0`>5<6sA>=o6saa3f94?7|@=<h7p`n2d83>4}O<?i0qco=f;295~N3>j1vbl=?:182M21k2wem>?50;3xL10d3tdj??4?:0yK03e<ugk8?7>51zJ72f=zfh9?6=4>{I65g>{ii:?1<7?tH54`?xhf;?0;6<uG47a8ykg4?3:1=vF;6b9~jd5?290:wE:9c:me6?=83;pD98l;|lb7d<728qC8;m4}oc0f?6=9rB?:n5rn`1`>5<6sA>=o6saa2f94?7|@=<h7p`n3d83>4}O<?i0qco<f;295~N3>j1vbl:?:182M21k2wem9?50;3xL10d3tdj8?4?:0yK03e<ugk??7>51zJ72f=zfh>?6=4>{I65g>{ii=?1<7?tH54`?xhf<?0;6<uG47a8ykg3?3:1=vF;6b9~jd2?290:wE:9c:me1?=83;pD98l;|lb0d<728qC8;m4}oc7f?6=9rB?:n5rn`6`>5<6sA>=o6saa5f94?7|@=<h7p`n4d83>4}O<?i0qco;f;295~N3>j1vbl;?:182M21k2wem8?50;3xL10d3tdj9?4?:0yK03e<ugk>?7>51zJ72f=zfh??6=4>{I65g>{ii<?1<7?tH54`?xhf=?0;6<uG47a8ykg2?3:1=vF;6b9~jd3?290:wE:9c:me0?=83;pD98l;|lb1d<728qC8;m4}oc6f?6=9rB?:n5rn`7`>5<6sA>=o6saa4f94?7|@=<h7p`n5d83>4}O<?i0qco:f;295~N3>j1vbl8?:182M21k2wem;?50;3xL10d3tdj:?4?:0yK03e<ugk=?7>51zJ72f=zfh<?6=4>{I65g>{ii??1<7?tH54`?xhf>?0;6<uG47a8ykg1?3:1=vF;6b9~jd0?290:wE:9c:me3?=83;pD98l;|lb2d<728qC8;m4}oc5f?6=9rB?:n5rn`4`>5<6sA>=o6saa7f94?7|@=<h7p`n6d83>4}O<?i0qco9f;295~N3>j1vbl9?:182M21k2wem:?50;3xL10d3tdj;?4?:0yK03e<ugk<?7>51zJ72f=zfh=?6=4>{I65g>{ii>?1<7?tH54`?xhf??0;6<uG47a8ykg0?3:1=vF;6b9~jd1?290:wE:9c:me2?=83;pD98l;|lb3d<728qC8;m4}oc4f?6=9rB?:n5rn`5`>5<6sA>=o6saa6f94?7|@=<h7p`n7d83>4}O<?i0qco8f;295~N3>j1vbl6?:182M21k2wem5?50;3xL10d3tdj4?4?:0yK03e<ugk3?7>51zJ72f=zfh2?6=4>{I65g>{ii1?1<7?tH54`?xhf0?0;6<uG47a8ykg??3:1=vF;6b9~jd>?290:wE:9c:me=?=83;pD98l;|lb<d<728qC8;m4}oc;f?6=9rB?:n5rn`:`>5<6sA>=o6saa9f94?7|@=<h7p`n8d83>4}O<?i0qco7f;295~N3>j1vbl7?:182M21k2wem4?50;3xL10d3tdj5?4?:0yK03e<ugk2?7>51zJ72f=zfh3?6=4>{I65g>{ii0?1<7?tH54`?xhf1?0;6<uG47a8ykg>?3:1=vF;6b9~jd??290:wE:9c:me<?=83;pD98l;|lb=d<728qC8;m4}oc:f?6=9rB?:n5rn`;`>5<6sA>=o6saa8f94?7|@=<h7p`n9d83>4}O<?i0qco6f;295~N3>j1vblo?:182M21k2weml?50;3xL10d3tdjm?4?:0yK03e<ugkj?7>51zJ72f=zfhk?6=4>{I65g>{iih?1<7?tH54`?xhfi?0;6<uG47a8ykgf?3:1=vF;6b9~jdg?290:wE:9c:med?=83;pD98l;|lbed<728qC8;m4}ocbf?6=9rB?:n5rn`c`>5<6sA>=o6saa`f94?7|@=<h7p`nad83>4}O<?i0qconf;295~N3>j1vbll?:182M21k2wemo?50;3xL10d3tdjn?4?:0yK03e<ugki?7>51zJ72f=zfhh?6=4>{I65g>{iik?1<7?tH54`?xhfj?0;6<uG47a8ykge?3:1=vF;6b9~jdd?290:wE:9c:meg?=83;pD98l;|lbfd<728qC8;m4}ocaf?6=9rB?:n5rn```>5<6sA>=o6saacf94?7|@=<h7p`nbd83>4}O<?i0qcomf;295~N3>j1vblm?:182M21k2wemn?50;3xL10d3tdjo?4?:0yK03e<ugkh?7>51zJ72f=zfhi?6=4>{I65g>{iij?1<7?tH54`?xhfk?0;6<uG47a8ykgd?3:1=vF;6b9~jde?290:wE:9c:mef?=83;pD98l;|lbgd<728qC8;m4}oc`f?6=9rB?:n5rn`a`>5<6sA>=o6saabf94?7|@=<h7p`ncd83>4}O<?i0qcolf;295~N3>j1vblj?:182M21k2wemi?50;3xL10d3tdjh?4?:0yK03e<ugko?7>51zJ72f=zfhn?6=4>{I65g>{iim?1<7?tH54`?xhfl?0;6<uG47a8ykgc?3:1=vF;6b9~jdb?290:wE:9c:mea?=83;pD98l;|lb`d<728qC8;m4}ocgf?6=9rB?:n5rn`f`>5<6sA>=o6saaef94?7|@=<h7p`ndd83>4}O<?i0qcokf;295~N3>j1vblk?:182M21k2wemh?50;3xL10d3tdji?4?:0yK03e<ugkn?7>51zJ72f=zfho?6=4>{I65g>{iil?1<7?tH54`?xhfm?0;6<uG47a8ykgb?3:1=vF;6b9~jdc?290:wE:9c:me`?=83;pD98l;|lbad<728qC8;m4}ocff?6=9rB?:n5rn`g`>5<6sA>=o6saadf94?7|@=<h7p`ned83>4}O<?i0qcojf;295~N3>j1vblh?:182M21k2wemk?50;3xL10d3tdjj?4?:0yK03e<ugkm?7>51zJ72f=zfhl?6=4>{I65g>{iio?1<7?tH54`?xhfn?0;6<uG47a8ykga?3:1=vF;6b9~jd`?290:wE:9c:mec?=83;pD98l;|lbbd<728qC8;m4}ocef?6=9rB?:n5rn`d`>5<6sA>=o6saagf94?7|@=<h7p`nfd83>4}O<?i0qcoif;295~N3>j1vbo>?:182M21k2wen=?50;3xL10d3tdi<?4?:0yK03e<ugh;?7>51zJ72f=zfk:?6=4>{I65g>{ij9?1<7?tH54`?xhe8?0;6<uG47a8ykd7?3:1=vF;6b9~jg6?290:wE:9c:mf5?=83;pD98l;|la4d<728qC8;m4}o`3f?6=9rB?:n5rnc2`>5<6sA>=o6sab1f94?7|@=<h7p`m0d83>4}O<?i0qcl?f;295~N3>j1vbo??:182M21k2wen<?50;3xL10d3tdi=?4?:0yK03e<ugh:?7>51zJ72f=zfk;?6=4>{I65g>{ij8?1<7?tH54`?xhe9?0;6<uG47a8ykd6?3:1=vF;6b9~jg7?290:wE:9c:mf4?=83;pD98l;|la5d<728qC8;m4}o`2f?6=9rB?:n5rnc3`>5<6sA>=o6sab0f94?7|@=<h7p`m1d83>4}O<?i0qcl>f;295~N3>j1vbo<?:182M21k2wen??50;3xL10d3tdi>?4?:0yK03e<ugh9?7>51zJ72f=zfk8?6=4>{I65g>{ij;?1<7?tH54`?xhe:?0;6<uG47a8ykd5?3:1=vF;6b9~jg4?290:wE:9c:mf7?=83;pD98l;|la6d<728qC8;m4}o`1f?6=9rB?:n5rnc0`>5<6sA>=o6sab3f94?7|@=<h7p`m2d83>4}O<?i0qcl=f;295~N3>j1vbo=?:182M21k2wen>?50;3xL10d3tdi??4?:0yK03e<ugh8?7>51zJ72f=zfk9?6=4>{I65g>{ij:?1<7?tH54`?xhe;?0;6<uG47a8ykd4?3:1=vF;6b9~jg5?290:wE:9c:mf6?=83;pD98l;|la7d<728qC8;m4}o`0f?6=9rB?:n5rnc1`>5<6sA>=o6sab2f94?7|@=<h7p`m3d83>4}O<?i0qcl<f;295~N3>j1vbo:?:182M21k2wen9?50;3xL10d3tdi8?4?:0yK03e<ugh??7>51zJ72f=zfk>?6=4>{I65g>{ij=?1<7?tH54`?xhe<?0;6<uG47a8ykd3?3:1=vF;6b9~jg2?290:wE:9c:mf1?=83;pD98l;|la0d<728qC8;m4}o`7f?6=9rB?:n5rnc6`>5<6sA>=o6sab5f94?7|@=<h7p`m4d83>4}O<?i0qcl;f;295~N3>j1vbo;?:182M21k2wen8?50;3xL10d3tdi9?4?:0yK03e<ugh>?7>51zJ72f=zfk??6=4>{I65g>{ij<?1<7?tH54`?xhe=?0;6<uG47a8ykd2?3:1=vF;6b9~jg3?290:wE:9c:mf0?=83;pD98l;|la1d<728qC8;m4}o`6f?6=9rB?:n5rnc7`>5<6sA>=o6sab4f94?7|@=<h7p`m5d83>4}O<?i0qcl:f;295~N3>j1vbo8?:182M21k2wen;?50;3xL10d3tdi:?4?:0yK03e<ugh=?7>51zJ72f=zfk<?6=4>{I65g>{ij??1<7?tH54`?xhe>?0;6<uG47a8ykd1?3:1=vF;6b9~jg0?290:wE:9c:mf3?=83;pD98l;|la2d<728qC8;m4}o`5f?6=9rB?:n5rnc4`>5<6sA>=o6sab7f94?7|@=<h7p`m6d83>4}O<?i0qcl9f;295~N3>j1vbo9?:182M21k2wen:?50;3xL10d3tdi;?4?:0yK03e<ugh<?7>51zJ72f=zfk=?6=4>{I65g>{ij>?1<7?tH54`?xhe??0;6<uG47a8ykd0?3:1=vF;6b9~jg1?290:wE:9c:mf2?=83;pD98l;|la3d<728qC8;m4}o`4f?6=9rB?:n5rnc5`>5<6sA>=o6sab6f94?7|@=<h7p`m7d83>4}O<?i0qcl8f;295~N3>j1vbo6?:182M21k2wen5?50;3xL10d3tdi4?4?:0yK03e<ugh3?7>51zJ72f=zfk2?6=4>{I65g>{ij1?1<7?tH54`?xhe0?0;6<uG47a8ykd??3:1=vF;6b9~jg>?290:wE:9c:mf=?=83;pD98l;|la<d<728qC8;m4}o`;f?6=9rB?:n5rnc:`>5<6sA>=o6sab9f94?7|@=<h7p`m8d83>4}O<?i0qcl7f;295~N3>j1vbo7?:182M21k2wen4?50;3xL10d3tdi5?4?:0yK03e<ugh2?7>51zJ72f=zfk3?6=4>{I65g>{ij0?1<7?tH54`?xhe1?0;6<uG47a8ykd>?3:1=vF;6b9~jg??290:wE:9c:mf<?=83;pD98l;|la=d<728qC8;m4}o`:f?6=9rB?:n5rnc;`>5<6sA>=o6sab8f94?7|@=<h7p`m9d83>4}O<?i0qcl6f;295~N3>j1vboo?:182M21k2wenl?50;3xL10d3tdim?4?:0yK03e<ughj?7>51zJ72f=zfkk?6=4>{I65g>{ijh?1<7?tH54`?xhei?0;6<uG47a8ykdf?3:1=vF;6b9~jgg?290:wE:9c:mfd?=83;pD98l;|laed<728qC8;m4}o`bf?6=9rB?:n5rncc`>5<6sA>=o6sab`f94?7|@=<h7p`mad83>4}O<?i0qclnf;295~N3>j1vbol?:182M21k2weno?50;3xL10d3tdin?4?:0yK03e<ughi?7>51zJ72f=zfkh?6=4>{I65g>{ijk?1<7?tH54`?xhej?0;6<uG47a8ykde?3:1=vF;6b9~jgd?290:wE:9c:mfg?=83;pD98l;|lafd<728qC8;m4}o`af?6=9rB?:n5r}|CDF}cm8028>><e6c~DED|8tJK\vsO@ \ No newline at end of file
diff --git a/fpga/usrp2/coregen/fifo_xlnx_1Kx18_2clk.v b/fpga/usrp2/coregen/fifo_xlnx_1Kx18_2clk.v
new file mode 100644
index 000000000..4737fb1bf
--- /dev/null
+++ b/fpga/usrp2/coregen/fifo_xlnx_1Kx18_2clk.v
@@ -0,0 +1,3819 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright (c) 1995-2008 Xilinx, Inc. All rights reserved.
+////////////////////////////////////////////////////////////////////////////////
+// ____ ____
+// / /\/ /
+// /___/ \ / Vendor: Xilinx
+// \ \ \/ Version: K.39
+// \ \ Application: netgen
+// / / Filename: fifo_xlnx_1Kx18_2clk.v
+// /___/ /\ Timestamp: Fri Jun 10 16:12:12 2011
+// \ \ / \
+// \___\/\___\
+//
+// Command : -intstyle ise -w -sim -ofmt verilog /tmp/_cg/fifo_xlnx_1Kx18_2clk.ngc /tmp/_cg/fifo_xlnx_1Kx18_2clk.v
+// Device : 3s2000fg456-5
+// Input file : /tmp/_cg/fifo_xlnx_1Kx18_2clk.ngc
+// Output file : /tmp/_cg/fifo_xlnx_1Kx18_2clk.v
+// # of Modules : 1
+// Design Name : fifo_xlnx_1Kx18_2clk
+// Xilinx : /opt/Xilinx/10.1/ISE
+//
+// Purpose:
+// This verilog netlist is a verification model and uses simulation
+// primitives which may not represent the true implementation of the
+// device, however the netlist is functionally correct and should not
+// be modified. This file cannot be synthesized and should only be used
+// with supported simulation tools.
+//
+// Reference:
+// Development System Reference Guide, Chapter 23 and Synthesis and Simulation Design Guide, Chapter 6
+//
+////////////////////////////////////////////////////////////////////////////////
+
+`timescale 1 ns/1 ps
+
+module fifo_xlnx_1Kx18_2clk (
+ rd_en, wr_en, full, empty, wr_clk, rst, rd_clk, wr_data_count, rd_data_count, dout, din
+);
+ input rd_en;
+ input wr_en;
+ output full;
+ output empty;
+ input wr_clk;
+ input rst;
+ input rd_clk;
+ output [10 : 0] wr_data_count;
+ output [10 : 0] rd_data_count;
+ output [17 : 0] dout;
+ input [17 : 0] din;
+
+ // synthesis translate_off
+
+ wire \BU2/U0/grf.rf/gl0.rd/ram_valid_fwft ;
+ wire \BU2/N39 ;
+ wire \BU2/N31 ;
+ wire \BU2/N37 ;
+ wire \BU2/N27 ;
+ wire \BU2/N25 ;
+ wire \BU2/N21 ;
+ wire \BU2/N19 ;
+ wire \BU2/N17 ;
+ wire \BU2/N11 ;
+ wire \BU2/N13 ;
+ wire \BU2/N36 ;
+ wire \BU2/N381 ;
+ wire \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/rd_dc_i_mux0002<9>4_470 ;
+ wire \BU2/N6 ;
+ wire \BU2/N7 ;
+ wire \BU2/N35 ;
+ wire \BU2/N41 ;
+ wire \BU2/N2 ;
+ wire \BU2/N40 ;
+ wire \BU2/N30 ;
+ wire \BU2/N4 ;
+ wire \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add0000_cy<9>_bdd4 ;
+ wire \BU2/N38 ;
+ wire \BU2/N33 ;
+ wire \BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin_xor0006_bdd0 ;
+ wire \BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin_xor0006_bdd0 ;
+ wire \BU2/N351 ;
+ wire \BU2/U0/grf.rf/mem/tmp_ram_rd_en ;
+ wire \BU2/U0/grf.rf/ram_regout_en ;
+ wire \BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy<0>_rt_425 ;
+ wire \BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy<1>_rt_424 ;
+ wire \BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy<2>_rt_422 ;
+ wire \BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy<3>_rt_420 ;
+ wire \BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy<4>_rt_418 ;
+ wire \BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy<5>_rt_416 ;
+ wire \BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy<6>_rt_414 ;
+ wire \BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy<7>_rt_412 ;
+ wire \BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy<8>_rt_410 ;
+ wire \BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_xor<9>_rt_408 ;
+ wire \BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count2 ;
+ wire \BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count ;
+ wire \BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count1 ;
+ wire \BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count3 ;
+ wire \BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count4 ;
+ wire \BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count7 ;
+ wire \BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count5 ;
+ wire \BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count6 ;
+ wire \BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count8 ;
+ wire \BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count9 ;
+ wire \BU2/U0/grf.rf/ram_wr_en ;
+ wire \BU2/U0/grf.rf/gl0.rd/gr1.rfwft/empty_fwft_fb_385 ;
+ wire \BU2/U0/grf.rf/gl0.rd/gr1.rfwft/empty_fwft_i_or0000 ;
+ wire \BU2/U0/grf.rf/gl0.rd/gr1.rfwft/user_valid_383 ;
+ wire \BU2/U0/grf.rf/gl0.rd/gr1.rfwft/curr_fwft_state_FSM_FFd1_382 ;
+ wire \BU2/U0/grf.rf/gl0.rd/gr1.rfwft/curr_fwft_state_FSM_FFd1-In ;
+ wire \BU2/U0/grf.rf/gl0.rd/gr1.rfwft/curr_fwft_state_FSM_FFd2_380 ;
+ wire \BU2/U0/grf.rf/gl0.rd/gr1.rfwft/curr_fwft_state_FSM_FFd2-In ;
+ wire \BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy<0>_rt_378 ;
+ wire \BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy<1>_rt_377 ;
+ wire \BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy<2>_rt_375 ;
+ wire \BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy<3>_rt_373 ;
+ wire \BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy<4>_rt_371 ;
+ wire \BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy<5>_rt_369 ;
+ wire \BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy<6>_rt_367 ;
+ wire \BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy<7>_rt_365 ;
+ wire \BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy<8>_rt_363 ;
+ wire \BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_xor<9>_rt_361 ;
+ wire \BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count2 ;
+ wire \BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count ;
+ wire \BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count1 ;
+ wire \BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count3 ;
+ wire \BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count4 ;
+ wire \BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count7 ;
+ wire \BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count5 ;
+ wire \BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count6 ;
+ wire \BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count8 ;
+ wire \BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count9 ;
+ wire \BU2/U0/grf.rf/ram_rd_en ;
+ wire \BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_xor0008 ;
+ wire \BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_xor0007 ;
+ wire \BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_xor0006 ;
+ wire \BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_xor0005 ;
+ wire \BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_xor0004 ;
+ wire \BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_xor0003 ;
+ wire \BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_xor0002 ;
+ wire \BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_xor0001 ;
+ wire \BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_xor0000 ;
+ wire \BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_xor0008 ;
+ wire \BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_xor0007 ;
+ wire \BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_xor0006 ;
+ wire \BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_xor0005 ;
+ wire \BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_xor0004 ;
+ wire \BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_xor0003 ;
+ wire \BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_xor0002 ;
+ wire \BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_xor0001 ;
+ wire \BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_xor0000 ;
+ wire \BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin_xor0008 ;
+ wire \BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin_xor0007 ;
+ wire \BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin_xor0006 ;
+ wire \BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin_xor0005 ;
+ wire \BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin_xor0004 ;
+ wire \BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin_xor0003 ;
+ wire \BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin_xor0002 ;
+ wire \BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin_xor0001 ;
+ wire \BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin_xor0000 ;
+ wire \BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin_xor0008 ;
+ wire \BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin_xor0007 ;
+ wire \BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin_xor0006 ;
+ wire \BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin_xor0005 ;
+ wire \BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin_xor0004 ;
+ wire \BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin_xor0003 ;
+ wire \BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin_xor0002 ;
+ wire \BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin_xor0001 ;
+ wire \BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin_xor0000 ;
+ wire \BU2/U0/grf.rf/gl0.wr/gwas.wsts/comp2 ;
+ wire \BU2/U0/grf.rf/gl0.wr/gwas.wsts/comp1 ;
+ wire \BU2/U0/grf.rf/gl0.rd/gras.rsts/comp1 ;
+ wire \BU2/U0/grf.rf/gl0.rd/gras.rsts/comp0 ;
+ wire \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add000016 ;
+ wire \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add000014 ;
+ wire \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add000012 ;
+ wire \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add000010 ;
+ wire \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add00008 ;
+ wire \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add00006 ;
+ wire \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add00004 ;
+ wire \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add00002 ;
+ wire \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add0000_cy[1] ;
+ wire \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub000016 ;
+ wire \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub000014 ;
+ wire \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub000012 ;
+ wire \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub000010 ;
+ wire \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub00008 ;
+ wire \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub00006 ;
+ wire \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub00004 ;
+ wire \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub00002 ;
+ wire \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add0000_cy[9] ;
+ wire \BU2/U0/grf.rf/gl0.wr/gwas.wsts/ram_full_fb_i_94 ;
+ wire \BU2/U0/grf.rf/gl0.wr/gwas.wsts/ram_full_i_or0000 ;
+ wire \BU2/U0/grf.rf/gl0.rd/gras.rsts/ram_empty_fb_i_81 ;
+ wire \BU2/U0/grf.rf/gl0.rd/gras.rsts/ram_empty_fb_i_or0000 ;
+ wire \BU2/U0/grf.rf/rstblk/wr_rst_comb ;
+ wire \BU2/U0/grf.rf/rstblk/rd_rst_comb ;
+ wire \BU2/U0/grf.rf/rstblk/wr_rst_asreg_72 ;
+ wire \BU2/U0/grf.rf/rstblk/rd_rst_asreg_71 ;
+ wire \BU2/U0/grf.rf/rstblk/wr_rst_asreg_d2_70 ;
+ wire \BU2/U0/grf.rf/rstblk/wr_rst_asreg_d1_69 ;
+ wire \BU2/U0/grf.rf/rstblk/rd_rst_asreg_d2_68 ;
+ wire \BU2/U0/grf.rf/rstblk/rd_rst_asreg_d1_67 ;
+ wire \BU2/N1 ;
+ wire NLW_VCC_P_UNCONNECTED;
+ wire NLW_GND_G_UNCONNECTED;
+ wire \NLW_BU2/U0/grf.rf/mem/gbm.gbmg.gbmga.ngecc.bmg/blk_mem_generator/valid.cstr/ramloop[0].ram.r/v2_noinit.ram/dp18x18.ram_DOA<15>_UNCONNECTED ;
+ wire \NLW_BU2/U0/grf.rf/mem/gbm.gbmg.gbmga.ngecc.bmg/blk_mem_generator/valid.cstr/ramloop[0].ram.r/v2_noinit.ram/dp18x18.ram_DOA<14>_UNCONNECTED ;
+ wire \NLW_BU2/U0/grf.rf/mem/gbm.gbmg.gbmga.ngecc.bmg/blk_mem_generator/valid.cstr/ramloop[0].ram.r/v2_noinit.ram/dp18x18.ram_DOA<13>_UNCONNECTED ;
+ wire \NLW_BU2/U0/grf.rf/mem/gbm.gbmg.gbmga.ngecc.bmg/blk_mem_generator/valid.cstr/ramloop[0].ram.r/v2_noinit.ram/dp18x18.ram_DOA<12>_UNCONNECTED ;
+ wire \NLW_BU2/U0/grf.rf/mem/gbm.gbmg.gbmga.ngecc.bmg/blk_mem_generator/valid.cstr/ramloop[0].ram.r/v2_noinit.ram/dp18x18.ram_DOA<11>_UNCONNECTED ;
+ wire \NLW_BU2/U0/grf.rf/mem/gbm.gbmg.gbmga.ngecc.bmg/blk_mem_generator/valid.cstr/ramloop[0].ram.r/v2_noinit.ram/dp18x18.ram_DOA<10>_UNCONNECTED ;
+ wire \NLW_BU2/U0/grf.rf/mem/gbm.gbmg.gbmga.ngecc.bmg/blk_mem_generator/valid.cstr/ramloop[0].ram.r/v2_noinit.ram/dp18x18.ram_DOA<9>_UNCONNECTED ;
+ wire \NLW_BU2/U0/grf.rf/mem/gbm.gbmg.gbmga.ngecc.bmg/blk_mem_generator/valid.cstr/ramloop[0].ram.r/v2_noinit.ram/dp18x18.ram_DOA<8>_UNCONNECTED ;
+ wire \NLW_BU2/U0/grf.rf/mem/gbm.gbmg.gbmga.ngecc.bmg/blk_mem_generator/valid.cstr/ramloop[0].ram.r/v2_noinit.ram/dp18x18.ram_DOA<7>_UNCONNECTED ;
+ wire \NLW_BU2/U0/grf.rf/mem/gbm.gbmg.gbmga.ngecc.bmg/blk_mem_generator/valid.cstr/ramloop[0].ram.r/v2_noinit.ram/dp18x18.ram_DOA<6>_UNCONNECTED ;
+ wire \NLW_BU2/U0/grf.rf/mem/gbm.gbmg.gbmga.ngecc.bmg/blk_mem_generator/valid.cstr/ramloop[0].ram.r/v2_noinit.ram/dp18x18.ram_DOA<5>_UNCONNECTED ;
+ wire \NLW_BU2/U0/grf.rf/mem/gbm.gbmg.gbmga.ngecc.bmg/blk_mem_generator/valid.cstr/ramloop[0].ram.r/v2_noinit.ram/dp18x18.ram_DOA<4>_UNCONNECTED ;
+ wire \NLW_BU2/U0/grf.rf/mem/gbm.gbmg.gbmga.ngecc.bmg/blk_mem_generator/valid.cstr/ramloop[0].ram.r/v2_noinit.ram/dp18x18.ram_DOA<3>_UNCONNECTED ;
+ wire \NLW_BU2/U0/grf.rf/mem/gbm.gbmg.gbmga.ngecc.bmg/blk_mem_generator/valid.cstr/ramloop[0].ram.r/v2_noinit.ram/dp18x18.ram_DOA<2>_UNCONNECTED ;
+ wire \NLW_BU2/U0/grf.rf/mem/gbm.gbmg.gbmga.ngecc.bmg/blk_mem_generator/valid.cstr/ramloop[0].ram.r/v2_noinit.ram/dp18x18.ram_DOA<1>_UNCONNECTED ;
+ wire \NLW_BU2/U0/grf.rf/mem/gbm.gbmg.gbmga.ngecc.bmg/blk_mem_generator/valid.cstr/ramloop[0].ram.r/v2_noinit.ram/dp18x18.ram_DOA<0>_UNCONNECTED ;
+ wire \NLW_BU2/U0/grf.rf/mem/gbm.gbmg.gbmga.ngecc.bmg/blk_mem_generator/valid.cstr/ramloop[0].ram.r/v2_noinit.ram/dp18x18.ram_DOPA<1>_UNCONNECTED ;
+ wire \NLW_BU2/U0/grf.rf/mem/gbm.gbmg.gbmga.ngecc.bmg/blk_mem_generator/valid.cstr/ramloop[0].ram.r/v2_noinit.ram/dp18x18.ram_DOPA<0>_UNCONNECTED ;
+ wire [17 : 0] din_2;
+ wire [17 : 0] dout_3;
+ wire [10 : 0] rd_data_count_4;
+ wire [10 : 0] wr_data_count_5;
+ wire [17 : 0] \BU2/U0/grf.rf/mem/dout_mem ;
+ wire [9 : 0] \BU2/U0/grf.rf/gl0.wr/wpntr/count_d1 ;
+ wire [8 : 0] \BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy ;
+ wire [9 : 0] \BU2/U0/grf.rf/gl0.wr/wpntr/count ;
+ wire [8 : 0] \BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy ;
+ wire [9 : 0] \BU2/U0/grf.rf/gl0.rd/rpntr/count ;
+ wire [9 : 0] \BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc ;
+ wire [9 : 0] \BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc ;
+ wire [9 : 0] \BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg_d1 ;
+ wire [9 : 0] \BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg ;
+ wire [9 : 0] \BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg_d1 ;
+ wire [9 : 0] \BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg ;
+ wire [4 : 0] \BU2/U0/grf.rf/gl0.wr/gwas.wsts/c2/v1 ;
+ wire [3 : 0] \BU2/U0/grf.rf/gl0.wr/gwas.wsts/c2/carrynet ;
+ wire [4 : 0] \BU2/U0/grf.rf/gl0.wr/gwas.wsts/c1/v1 ;
+ wire [3 : 0] \BU2/U0/grf.rf/gl0.wr/gwas.wsts/c1/carrynet ;
+ wire [4 : 0] \BU2/U0/grf.rf/gl0.rd/gras.rsts/c1/v1 ;
+ wire [3 : 0] \BU2/U0/grf.rf/gl0.rd/gras.rsts/c1/carrynet ;
+ wire [4 : 0] \BU2/U0/grf.rf/gl0.rd/gras.rsts/c0/v1 ;
+ wire [3 : 0] \BU2/U0/grf.rf/gl0.rd/gras.rsts/c0/carrynet ;
+ wire [9 : 0] \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_lut ;
+ wire [9 : 0] \BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin ;
+ wire [9 : 0] \BU2/U0/grf.rf/gl0.wr/wpntr/count_d2 ;
+ wire [8 : 0] \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_cy ;
+ wire [9 : 0] \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_lut ;
+ wire [9 : 0] \BU2/U0/grf.rf/gl0.rd/rpntr/count_d1 ;
+ wire [9 : 0] \BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin ;
+ wire [8 : 0] \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_cy ;
+ wire [1 : 1] \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub0000_cy ;
+ wire [0 : 0] \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/diff_wr_rd_tmp ;
+ wire [9 : 1] \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/wr_data_count_i_add0000 ;
+ wire [0 : 0] \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/diff_wr_rd_tmp ;
+ wire [10 : 0] \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/rd_dc_i_mux0002 ;
+ wire [1 : 0] \BU2/U0/grf.rf/rstblk/wr_rst_reg ;
+ wire [2 : 0] \BU2/U0/grf.rf/rstblk/rd_rst_reg ;
+ wire [0 : 0] \BU2/data_count ;
+ assign
+ wr_data_count[10] = wr_data_count_5[10],
+ wr_data_count[9] = wr_data_count_5[9],
+ wr_data_count[8] = wr_data_count_5[8],
+ wr_data_count[7] = wr_data_count_5[7],
+ wr_data_count[6] = wr_data_count_5[6],
+ wr_data_count[5] = wr_data_count_5[5],
+ wr_data_count[4] = wr_data_count_5[4],
+ wr_data_count[3] = wr_data_count_5[3],
+ wr_data_count[2] = wr_data_count_5[2],
+ wr_data_count[1] = wr_data_count_5[1],
+ wr_data_count[0] = wr_data_count_5[0],
+ rd_data_count[10] = rd_data_count_4[10],
+ rd_data_count[9] = rd_data_count_4[9],
+ rd_data_count[8] = rd_data_count_4[8],
+ rd_data_count[7] = rd_data_count_4[7],
+ rd_data_count[6] = rd_data_count_4[6],
+ rd_data_count[5] = rd_data_count_4[5],
+ rd_data_count[4] = rd_data_count_4[4],
+ rd_data_count[3] = rd_data_count_4[3],
+ rd_data_count[2] = rd_data_count_4[2],
+ rd_data_count[1] = rd_data_count_4[1],
+ rd_data_count[0] = rd_data_count_4[0],
+ dout[17] = dout_3[17],
+ dout[16] = dout_3[16],
+ dout[15] = dout_3[15],
+ dout[14] = dout_3[14],
+ dout[13] = dout_3[13],
+ dout[12] = dout_3[12],
+ dout[11] = dout_3[11],
+ dout[10] = dout_3[10],
+ dout[9] = dout_3[9],
+ dout[8] = dout_3[8],
+ dout[7] = dout_3[7],
+ dout[6] = dout_3[6],
+ dout[5] = dout_3[5],
+ dout[4] = dout_3[4],
+ dout[3] = dout_3[3],
+ dout[2] = dout_3[2],
+ dout[1] = dout_3[1],
+ dout[0] = dout_3[0],
+ din_2[17] = din[17],
+ din_2[16] = din[16],
+ din_2[15] = din[15],
+ din_2[14] = din[14],
+ din_2[13] = din[13],
+ din_2[12] = din[12],
+ din_2[11] = din[11],
+ din_2[10] = din[10],
+ din_2[9] = din[9],
+ din_2[8] = din[8],
+ din_2[7] = din[7],
+ din_2[6] = din[6],
+ din_2[5] = din[5],
+ din_2[4] = din[4],
+ din_2[3] = din[3],
+ din_2[2] = din[2],
+ din_2[1] = din[1],
+ din_2[0] = din[0];
+ VCC VCC_0 (
+ .P(NLW_VCC_P_UNCONNECTED)
+ );
+ GND GND_1 (
+ .G(NLW_GND_G_UNCONNECTED)
+ );
+ LUT4_D #(
+ .INIT ( 16'h0440 ))
+ \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/rd_dc_i_mux0002<9>31 (
+ .I0(\BU2/U0/grf.rf/rstblk/rd_rst_reg [2]),
+ .I1(\BU2/U0/grf.rf/gl0.rd/gr1.rfwft/user_valid_383 ),
+ .I2(\BU2/U0/grf.rf/gl0.rd/gr1.rfwft/curr_fwft_state_FSM_FFd1_382 ),
+ .I3(\BU2/U0/grf.rf/gl0.rd/gr1.rfwft/curr_fwft_state_FSM_FFd2_380 ),
+ .LO(\BU2/N40 ),
+ .O(\BU2/N33 )
+ );
+ LUT4_L #(
+ .INIT ( 16'h8000 ))
+ \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/rd_dc_i_mux0002<8>_SW1_SW0 (
+ .I0(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub0000_cy [1]),
+ .I1(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub00002 ),
+ .I2(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub00004 ),
+ .I3(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub00006 ),
+ .LO(\BU2/N31 )
+ );
+ LUT3_D #(
+ .INIT ( 8'h80 ))
+ \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/wr_data_count_i_add0000<9>_SW0_SW0 (
+ .I0(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add00008 ),
+ .I1(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add000010 ),
+ .I2(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add000012 ),
+ .LO(\BU2/N39 ),
+ .O(\BU2/N27 )
+ );
+ LUT4_L #(
+ .INIT ( 16'h8000 ))
+ \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/rd_dc_i_mux0002<9>21_SW1 (
+ .I0(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub00002 ),
+ .I1(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub00004 ),
+ .I2(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub00006 ),
+ .I3(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub00008 ),
+ .LO(\BU2/N19 )
+ );
+ LUT3_L #(
+ .INIT ( 8'h80 ))
+ \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/rd_dc_i_mux0002<9>21_SW0 (
+ .I0(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub00002 ),
+ .I1(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub00004 ),
+ .I2(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub00006 ),
+ .LO(\BU2/N17 )
+ );
+ LUT4_D #(
+ .INIT ( 16'h2000 ))
+ \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/rd_dc_i_mux0002<4>111_SW0 (
+ .I0(\BU2/U0/grf.rf/gl0.rd/gr1.rfwft/user_valid_383 ),
+ .I1(\BU2/U0/grf.rf/rstblk/rd_rst_reg [2]),
+ .I2(\BU2/U0/grf.rf/gl0.rd/ram_valid_fwft ),
+ .I3(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub0000_cy [1]),
+ .LO(\BU2/N381 ),
+ .O(\BU2/N11 )
+ );
+ LUT3_D #(
+ .INIT ( 8'h80 ))
+ \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/rd_dc_i_mux0002<9>41_SW0 (
+ .I0(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub000012 ),
+ .I1(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub000010 ),
+ .I2(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub00008 ),
+ .LO(\BU2/N37 ),
+ .O(\BU2/N13 )
+ );
+ LUT3_D #(
+ .INIT ( 8'h7F ))
+ \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/rd_dc_i_mux0002<4>111 (
+ .I0(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub0000_cy [1]),
+ .I1(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub00002 ),
+ .I2(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub00004 ),
+ .LO(\BU2/N36 ),
+ .O(\BU2/N38 )
+ );
+ LUT2_D #(
+ .INIT ( 4'h6 ))
+ \BU2/U0/grf.rf/gl0.rd/gr1.rfwft/RAM_VALID_FWFT11 (
+ .I0(\BU2/U0/grf.rf/gl0.rd/gr1.rfwft/curr_fwft_state_FSM_FFd1_382 ),
+ .I1(\BU2/U0/grf.rf/gl0.rd/gr1.rfwft/curr_fwft_state_FSM_FFd2_380 ),
+ .LO(\BU2/N351 ),
+ .O(\BU2/U0/grf.rf/gl0.rd/ram_valid_fwft )
+ );
+ RAMB16_S18_S18 #(
+ .INIT_3E ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ),
+ .INIT_3F ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ),
+ .INITP_00 ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ),
+ .INITP_01 ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ),
+ .INITP_02 ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ),
+ .INITP_03 ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ),
+ .INITP_04 ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ),
+ .INITP_05 ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ),
+ .SRVAL_A ( 18'h00000 ),
+ .SRVAL_B ( 18'h00000 ),
+ .INIT_00 ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ),
+ .INIT_01 ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ),
+ .INIT_02 ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ),
+ .INIT_03 ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ),
+ .INIT_04 ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ),
+ .INIT_05 ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ),
+ .INIT_06 ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ),
+ .INIT_07 ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ),
+ .INIT_08 ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ),
+ .INIT_09 ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ),
+ .INIT_0A ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ),
+ .INIT_0B ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ),
+ .INIT_0C ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ),
+ .INIT_0D ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ),
+ .INIT_0E ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ),
+ .INIT_0F ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ),
+ .INIT_10 ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ),
+ .INIT_11 ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ),
+ .INIT_12 ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ),
+ .INIT_13 ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ),
+ .INIT_14 ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ),
+ .INIT_15 ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ),
+ .INIT_16 ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ),
+ .INIT_17 ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ),
+ .INIT_18 ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ),
+ .INIT_19 ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ),
+ .INIT_1A ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ),
+ .INIT_1B ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ),
+ .INIT_1C ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ),
+ .INIT_1D ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ),
+ .INIT_1E ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ),
+ .INIT_1F ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ),
+ .INIT_20 ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ),
+ .INIT_21 ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ),
+ .INIT_22 ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ),
+ .INIT_23 ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ),
+ .INIT_24 ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ),
+ .INIT_25 ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ),
+ .INIT_26 ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ),
+ .INIT_27 ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ),
+ .INIT_28 ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ),
+ .INIT_29 ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ),
+ .INIT_2A ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ),
+ .INIT_2B ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ),
+ .INIT_2C ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ),
+ .INIT_2D ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ),
+ .INIT_2E ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ),
+ .INIT_2F ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ),
+ .INIT_30 ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ),
+ .INIT_31 ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ),
+ .INIT_32 ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ),
+ .INIT_33 ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ),
+ .INIT_34 ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ),
+ .INIT_35 ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ),
+ .INIT_36 ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ),
+ .INIT_37 ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ),
+ .INIT_38 ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ),
+ .INIT_39 ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ),
+ .INIT_3A ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ),
+ .INIT_3B ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ),
+ .INIT_3C ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ),
+ .INIT_3D ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ),
+ .WRITE_MODE_B ( "WRITE_FIRST" ),
+ .INITP_06 ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ),
+ .SIM_COLLISION_CHECK ( "NONE" ),
+ .INIT_A ( 18'h00000 ),
+ .INIT_B ( 18'h00000 ),
+ .WRITE_MODE_A ( "WRITE_FIRST" ),
+ .INITP_07 ( 256'h0000000000000000000000000000000000000000000000000000000000000000 ))
+ \BU2/U0/grf.rf/mem/gbm.gbmg.gbmga.ngecc.bmg/blk_mem_generator/valid.cstr/ramloop[0].ram.r/v2_noinit.ram/dp18x18.ram (
+ .CLKA(wr_clk),
+ .CLKB(rd_clk),
+ .ENA(\BU2/N1 ),
+ .ENB(\BU2/U0/grf.rf/mem/tmp_ram_rd_en ),
+ .SSRA(\BU2/data_count [0]),
+ .SSRB(\BU2/U0/grf.rf/rstblk/rd_rst_reg [0]),
+ .WEA(\BU2/U0/grf.rf/ram_wr_en ),
+ .WEB(\BU2/data_count [0]),
+ .ADDRA({\BU2/U0/grf.rf/gl0.wr/wpntr/count_d2 [9], \BU2/U0/grf.rf/gl0.wr/wpntr/count_d2 [8], \BU2/U0/grf.rf/gl0.wr/wpntr/count_d2 [7],
+\BU2/U0/grf.rf/gl0.wr/wpntr/count_d2 [6], \BU2/U0/grf.rf/gl0.wr/wpntr/count_d2 [5], \BU2/U0/grf.rf/gl0.wr/wpntr/count_d2 [4],
+\BU2/U0/grf.rf/gl0.wr/wpntr/count_d2 [3], \BU2/U0/grf.rf/gl0.wr/wpntr/count_d2 [2], \BU2/U0/grf.rf/gl0.wr/wpntr/count_d2 [1],
+\BU2/U0/grf.rf/gl0.wr/wpntr/count_d2 [0]}),
+ .ADDRB({\BU2/U0/grf.rf/gl0.rd/rpntr/count_d1 [9], \BU2/U0/grf.rf/gl0.rd/rpntr/count_d1 [8], \BU2/U0/grf.rf/gl0.rd/rpntr/count_d1 [7],
+\BU2/U0/grf.rf/gl0.rd/rpntr/count_d1 [6], \BU2/U0/grf.rf/gl0.rd/rpntr/count_d1 [5], \BU2/U0/grf.rf/gl0.rd/rpntr/count_d1 [4],
+\BU2/U0/grf.rf/gl0.rd/rpntr/count_d1 [3], \BU2/U0/grf.rf/gl0.rd/rpntr/count_d1 [2], \BU2/U0/grf.rf/gl0.rd/rpntr/count_d1 [1],
+\BU2/U0/grf.rf/gl0.rd/rpntr/count_d1 [0]}),
+ .DIA({din_2[16], din_2[15], din_2[14], din_2[13], din_2[12], din_2[11], din_2[10], din_2[9], din_2[7], din_2[6], din_2[5], din_2[4], din_2[3],
+din_2[2], din_2[1], din_2[0]}),
+ .DIB({\BU2/data_count [0], \BU2/data_count [0], \BU2/data_count [0], \BU2/data_count [0], \BU2/data_count [0], \BU2/data_count [0],
+\BU2/data_count [0], \BU2/data_count [0], \BU2/data_count [0], \BU2/data_count [0], \BU2/data_count [0], \BU2/data_count [0], \BU2/data_count [0],
+\BU2/data_count [0], \BU2/data_count [0], \BU2/data_count [0]}),
+ .DIPA({din_2[17], din_2[8]}),
+ .DIPB({\BU2/data_count [0], \BU2/data_count [0]}),
+ .DOA({\NLW_BU2/U0/grf.rf/mem/gbm.gbmg.gbmga.ngecc.bmg/blk_mem_generator/valid.cstr/ramloop[0].ram.r/v2_noinit.ram/dp18x18.ram_DOA<15>_UNCONNECTED
+, \NLW_BU2/U0/grf.rf/mem/gbm.gbmg.gbmga.ngecc.bmg/blk_mem_generator/valid.cstr/ramloop[0].ram.r/v2_noinit.ram/dp18x18.ram_DOA<14>_UNCONNECTED ,
+\NLW_BU2/U0/grf.rf/mem/gbm.gbmg.gbmga.ngecc.bmg/blk_mem_generator/valid.cstr/ramloop[0].ram.r/v2_noinit.ram/dp18x18.ram_DOA<13>_UNCONNECTED ,
+\NLW_BU2/U0/grf.rf/mem/gbm.gbmg.gbmga.ngecc.bmg/blk_mem_generator/valid.cstr/ramloop[0].ram.r/v2_noinit.ram/dp18x18.ram_DOA<12>_UNCONNECTED ,
+\NLW_BU2/U0/grf.rf/mem/gbm.gbmg.gbmga.ngecc.bmg/blk_mem_generator/valid.cstr/ramloop[0].ram.r/v2_noinit.ram/dp18x18.ram_DOA<11>_UNCONNECTED ,
+\NLW_BU2/U0/grf.rf/mem/gbm.gbmg.gbmga.ngecc.bmg/blk_mem_generator/valid.cstr/ramloop[0].ram.r/v2_noinit.ram/dp18x18.ram_DOA<10>_UNCONNECTED ,
+\NLW_BU2/U0/grf.rf/mem/gbm.gbmg.gbmga.ngecc.bmg/blk_mem_generator/valid.cstr/ramloop[0].ram.r/v2_noinit.ram/dp18x18.ram_DOA<9>_UNCONNECTED ,
+\NLW_BU2/U0/grf.rf/mem/gbm.gbmg.gbmga.ngecc.bmg/blk_mem_generator/valid.cstr/ramloop[0].ram.r/v2_noinit.ram/dp18x18.ram_DOA<8>_UNCONNECTED ,
+\NLW_BU2/U0/grf.rf/mem/gbm.gbmg.gbmga.ngecc.bmg/blk_mem_generator/valid.cstr/ramloop[0].ram.r/v2_noinit.ram/dp18x18.ram_DOA<7>_UNCONNECTED ,
+\NLW_BU2/U0/grf.rf/mem/gbm.gbmg.gbmga.ngecc.bmg/blk_mem_generator/valid.cstr/ramloop[0].ram.r/v2_noinit.ram/dp18x18.ram_DOA<6>_UNCONNECTED ,
+\NLW_BU2/U0/grf.rf/mem/gbm.gbmg.gbmga.ngecc.bmg/blk_mem_generator/valid.cstr/ramloop[0].ram.r/v2_noinit.ram/dp18x18.ram_DOA<5>_UNCONNECTED ,
+\NLW_BU2/U0/grf.rf/mem/gbm.gbmg.gbmga.ngecc.bmg/blk_mem_generator/valid.cstr/ramloop[0].ram.r/v2_noinit.ram/dp18x18.ram_DOA<4>_UNCONNECTED ,
+\NLW_BU2/U0/grf.rf/mem/gbm.gbmg.gbmga.ngecc.bmg/blk_mem_generator/valid.cstr/ramloop[0].ram.r/v2_noinit.ram/dp18x18.ram_DOA<3>_UNCONNECTED ,
+\NLW_BU2/U0/grf.rf/mem/gbm.gbmg.gbmga.ngecc.bmg/blk_mem_generator/valid.cstr/ramloop[0].ram.r/v2_noinit.ram/dp18x18.ram_DOA<2>_UNCONNECTED ,
+\NLW_BU2/U0/grf.rf/mem/gbm.gbmg.gbmga.ngecc.bmg/blk_mem_generator/valid.cstr/ramloop[0].ram.r/v2_noinit.ram/dp18x18.ram_DOA<1>_UNCONNECTED ,
+\NLW_BU2/U0/grf.rf/mem/gbm.gbmg.gbmga.ngecc.bmg/blk_mem_generator/valid.cstr/ramloop[0].ram.r/v2_noinit.ram/dp18x18.ram_DOA<0>_UNCONNECTED }),
+ .DOPA({
+\NLW_BU2/U0/grf.rf/mem/gbm.gbmg.gbmga.ngecc.bmg/blk_mem_generator/valid.cstr/ramloop[0].ram.r/v2_noinit.ram/dp18x18.ram_DOPA<1>_UNCONNECTED ,
+\NLW_BU2/U0/grf.rf/mem/gbm.gbmg.gbmga.ngecc.bmg/blk_mem_generator/valid.cstr/ramloop[0].ram.r/v2_noinit.ram/dp18x18.ram_DOPA<0>_UNCONNECTED }),
+ .DOB({\BU2/U0/grf.rf/mem/dout_mem [16], \BU2/U0/grf.rf/mem/dout_mem [15], \BU2/U0/grf.rf/mem/dout_mem [14], \BU2/U0/grf.rf/mem/dout_mem [13],
+\BU2/U0/grf.rf/mem/dout_mem [12], \BU2/U0/grf.rf/mem/dout_mem [11], \BU2/U0/grf.rf/mem/dout_mem [10], \BU2/U0/grf.rf/mem/dout_mem [9],
+\BU2/U0/grf.rf/mem/dout_mem [7], \BU2/U0/grf.rf/mem/dout_mem [6], \BU2/U0/grf.rf/mem/dout_mem [5], \BU2/U0/grf.rf/mem/dout_mem [4],
+\BU2/U0/grf.rf/mem/dout_mem [3], \BU2/U0/grf.rf/mem/dout_mem [2], \BU2/U0/grf.rf/mem/dout_mem [1], \BU2/U0/grf.rf/mem/dout_mem [0]}),
+ .DOPB({\BU2/U0/grf.rf/mem/dout_mem [17], \BU2/U0/grf.rf/mem/dout_mem [8]})
+ );
+ INV \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add0000_xor<1>11_INV_0 (
+ .I(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add0000_cy[1] ),
+ .O(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/wr_data_count_i_add0000 [1])
+ );
+ LUT4 #(
+ .INIT ( 16'h8000 ))
+ \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add0000_cy<9> (
+ .I0(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add000014 ),
+ .I1(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add000016 ),
+ .I2(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add0000_cy<9>_bdd4 ),
+ .I3(\BU2/N39 ),
+ .O(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add0000_cy[9] )
+ );
+ LUT4 #(
+ .INIT ( 16'h7FFF ))
+ \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/rd_dc_i_mux0002<8>_SW1 (
+ .I0(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub000012 ),
+ .I1(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub000010 ),
+ .I2(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub00008 ),
+ .I3(\BU2/N31 ),
+ .O(\BU2/N7 )
+ );
+ LUT4 #(
+ .INIT ( 16'hA2AA ))
+ \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/rd_dc_i_mux0002<9>30_SW0 (
+ .I0(\BU2/N33 ),
+ .I1(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub000014 ),
+ .I2(\BU2/N4 ),
+ .I3(\BU2/N37 ),
+ .O(\BU2/N21 )
+ );
+ LUT4 #(
+ .INIT ( 16'h6CCC ))
+ \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/wr_data_count_i_add0000<9> (
+ .I0(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add000014 ),
+ .I1(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add000016 ),
+ .I2(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add0000_cy<9>_bdd4 ),
+ .I3(\BU2/N27 ),
+ .O(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/wr_data_count_i_add0000 [9])
+ );
+ LUT4 #(
+ .INIT ( 16'h6CCC ))
+ \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/wr_data_count_i_add0000<8>1 (
+ .I0(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add000012 ),
+ .I1(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add000014 ),
+ .I2(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add0000_cy<9>_bdd4 ),
+ .I3(\BU2/N25 ),
+ .O(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/wr_data_count_i_add0000 [8])
+ );
+ LUT2 #(
+ .INIT ( 4'h8 ))
+ \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add0000_cy<9>31_SW1 (
+ .I0(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add00008 ),
+ .I1(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add000010 ),
+ .O(\BU2/N25 )
+ );
+ LUT4 #(
+ .INIT ( 16'hEAC0 ))
+ \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/rd_dc_i_mux0002<9>38 (
+ .I0(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub000016 ),
+ .I1(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/rd_dc_i_mux0002<9>4_470 ),
+ .I2(\BU2/N35 ),
+ .I3(\BU2/N21 ),
+ .O(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/rd_dc_i_mux0002 [9])
+ );
+ LUT4 #(
+ .INIT ( 16'h8000 ))
+ \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/rd_dc_i_mux0002<8>_SW0 (
+ .I0(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub000012 ),
+ .I1(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub000010 ),
+ .I2(\BU2/N11 ),
+ .I3(\BU2/N19 ),
+ .O(\BU2/N6 )
+ );
+ LUT4 #(
+ .INIT ( 16'h8000 ))
+ \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/rd_dc_i_mux0002<9>41 (
+ .I0(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub000010 ),
+ .I1(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub00008 ),
+ .I2(\BU2/N11 ),
+ .I3(\BU2/N17 ),
+ .O(\BU2/N35 )
+ );
+ LUT4 #(
+ .INIT ( 16'h7FFF ))
+ \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/rd_dc_i_mux0002<5>11 (
+ .I0(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub0000_cy [1]),
+ .I1(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub00002 ),
+ .I2(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub00004 ),
+ .I3(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub00006 ),
+ .O(\BU2/N4 )
+ );
+ LUT4 #(
+ .INIT ( 16'h8000 ))
+ \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/rd_dc_i_mux0002<10>1 (
+ .I0(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub000014 ),
+ .I1(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub000016 ),
+ .I2(\BU2/N13 ),
+ .I3(\BU2/N30 ),
+ .O(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/rd_dc_i_mux0002 [10])
+ );
+ LUT4 #(
+ .INIT ( 16'hFF7F ))
+ \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/rd_dc_i_mux0002<7>_SW0 (
+ .I0(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub000010 ),
+ .I1(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub00008 ),
+ .I2(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub00006 ),
+ .I3(\BU2/N36 ),
+ .O(\BU2/N41 )
+ );
+ LUT4 #(
+ .INIT ( 16'h8000 ))
+ \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/rd_dc_i_mux0002<9>21 (
+ .I0(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub00006 ),
+ .I1(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub00004 ),
+ .I2(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub00002 ),
+ .I3(\BU2/N381 ),
+ .O(\BU2/N30 )
+ );
+ LUT1 #(
+ .INIT ( 2'h2 ))
+ \BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_xor<9>_rt (
+ .I0(\BU2/U0/grf.rf/gl0.wr/wpntr/count [9]),
+ .O(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_xor<9>_rt_408 )
+ );
+ LUT1 #(
+ .INIT ( 2'h2 ))
+ \BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_xor<9>_rt (
+ .I0(\BU2/U0/grf.rf/gl0.rd/rpntr/count [9]),
+ .O(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_xor<9>_rt_361 )
+ );
+ LUT1 #(
+ .INIT ( 2'h2 ))
+ \BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy<0>_rt (
+ .I0(\BU2/U0/grf.rf/gl0.wr/wpntr/count [0]),
+ .O(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy<0>_rt_425 )
+ );
+ LUT1 #(
+ .INIT ( 2'h2 ))
+ \BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy<1>_rt (
+ .I0(\BU2/U0/grf.rf/gl0.wr/wpntr/count [1]),
+ .O(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy<1>_rt_424 )
+ );
+ LUT1 #(
+ .INIT ( 2'h2 ))
+ \BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy<2>_rt (
+ .I0(\BU2/U0/grf.rf/gl0.wr/wpntr/count [2]),
+ .O(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy<2>_rt_422 )
+ );
+ LUT1 #(
+ .INIT ( 2'h2 ))
+ \BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy<3>_rt (
+ .I0(\BU2/U0/grf.rf/gl0.wr/wpntr/count [3]),
+ .O(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy<3>_rt_420 )
+ );
+ LUT1 #(
+ .INIT ( 2'h2 ))
+ \BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy<4>_rt (
+ .I0(\BU2/U0/grf.rf/gl0.wr/wpntr/count [4]),
+ .O(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy<4>_rt_418 )
+ );
+ LUT1 #(
+ .INIT ( 2'h2 ))
+ \BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy<5>_rt (
+ .I0(\BU2/U0/grf.rf/gl0.wr/wpntr/count [5]),
+ .O(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy<5>_rt_416 )
+ );
+ LUT1 #(
+ .INIT ( 2'h2 ))
+ \BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy<6>_rt (
+ .I0(\BU2/U0/grf.rf/gl0.wr/wpntr/count [6]),
+ .O(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy<6>_rt_414 )
+ );
+ LUT1 #(
+ .INIT ( 2'h2 ))
+ \BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy<7>_rt (
+ .I0(\BU2/U0/grf.rf/gl0.wr/wpntr/count [7]),
+ .O(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy<7>_rt_412 )
+ );
+ LUT1 #(
+ .INIT ( 2'h2 ))
+ \BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy<8>_rt (
+ .I0(\BU2/U0/grf.rf/gl0.wr/wpntr/count [8]),
+ .O(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy<8>_rt_410 )
+ );
+ LUT1 #(
+ .INIT ( 2'h2 ))
+ \BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy<0>_rt (
+ .I0(\BU2/U0/grf.rf/gl0.rd/rpntr/count [0]),
+ .O(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy<0>_rt_378 )
+ );
+ LUT1 #(
+ .INIT ( 2'h2 ))
+ \BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy<1>_rt (
+ .I0(\BU2/U0/grf.rf/gl0.rd/rpntr/count [1]),
+ .O(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy<1>_rt_377 )
+ );
+ LUT1 #(
+ .INIT ( 2'h2 ))
+ \BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy<2>_rt (
+ .I0(\BU2/U0/grf.rf/gl0.rd/rpntr/count [2]),
+ .O(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy<2>_rt_375 )
+ );
+ LUT1 #(
+ .INIT ( 2'h2 ))
+ \BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy<3>_rt (
+ .I0(\BU2/U0/grf.rf/gl0.rd/rpntr/count [3]),
+ .O(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy<3>_rt_373 )
+ );
+ LUT1 #(
+ .INIT ( 2'h2 ))
+ \BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy<4>_rt (
+ .I0(\BU2/U0/grf.rf/gl0.rd/rpntr/count [4]),
+ .O(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy<4>_rt_371 )
+ );
+ LUT1 #(
+ .INIT ( 2'h2 ))
+ \BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy<5>_rt (
+ .I0(\BU2/U0/grf.rf/gl0.rd/rpntr/count [5]),
+ .O(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy<5>_rt_369 )
+ );
+ LUT1 #(
+ .INIT ( 2'h2 ))
+ \BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy<6>_rt (
+ .I0(\BU2/U0/grf.rf/gl0.rd/rpntr/count [6]),
+ .O(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy<6>_rt_367 )
+ );
+ LUT1 #(
+ .INIT ( 2'h2 ))
+ \BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy<7>_rt (
+ .I0(\BU2/U0/grf.rf/gl0.rd/rpntr/count [7]),
+ .O(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy<7>_rt_365 )
+ );
+ LUT1 #(
+ .INIT ( 2'h2 ))
+ \BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy<8>_rt (
+ .I0(\BU2/U0/grf.rf/gl0.rd/rpntr/count [8]),
+ .O(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy<8>_rt_363 )
+ );
+ LUT4 #(
+ .INIT ( 16'h8000 ))
+ \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add0000_cy<9>41 (
+ .I0(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add0000_cy[1] ),
+ .I1(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add00002 ),
+ .I2(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add00004 ),
+ .I3(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add00006 ),
+ .O(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add0000_cy<9>_bdd4 )
+ );
+ LUT3 #(
+ .INIT ( 8'h08 ))
+ \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/rd_dc_i_mux0002<9>4 (
+ .I0(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub000012 ),
+ .I1(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub000014 ),
+ .I2(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub000016 ),
+ .O(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/rd_dc_i_mux0002<9>4_470 )
+ );
+ LUT4 #(
+ .INIT ( 16'hD580 ))
+ \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/rd_dc_i_mux0002<8> (
+ .I0(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub000014 ),
+ .I1(\BU2/N33 ),
+ .I2(\BU2/N7 ),
+ .I3(\BU2/N6 ),
+ .O(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/rd_dc_i_mux0002 [8])
+ );
+ LUT4 #(
+ .INIT ( 16'hD580 ))
+ \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/rd_dc_i_mux0002<7> (
+ .I0(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub000012 ),
+ .I1(\BU2/N33 ),
+ .I2(\BU2/N41 ),
+ .I3(\BU2/N35 ),
+ .O(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/rd_dc_i_mux0002 [7])
+ );
+ LUT4 #(
+ .INIT ( 16'hEA40 ))
+ \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/rd_dc_i_mux0002<6> (
+ .I0(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub000010 ),
+ .I1(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub00008 ),
+ .I2(\BU2/N30 ),
+ .I3(\BU2/N2 ),
+ .O(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/rd_dc_i_mux0002 [6])
+ );
+ LUT4 #(
+ .INIT ( 16'hAA2A ))
+ \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/rd_dc_i_mux0002<6>_SW0 (
+ .I0(\BU2/N40 ),
+ .I1(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub00008 ),
+ .I2(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub00006 ),
+ .I3(\BU2/N38 ),
+ .O(\BU2/N2 )
+ );
+ LUT4 #(
+ .INIT ( 16'hD580 ))
+ \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/rd_dc_i_mux0002<5>2 (
+ .I0(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub00008 ),
+ .I1(\BU2/N4 ),
+ .I2(\BU2/N33 ),
+ .I3(\BU2/N30 ),
+ .O(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/rd_dc_i_mux0002 [5])
+ );
+ LUT4 #(
+ .INIT ( 16'h6CCC ))
+ \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/wr_data_count_i_add0000<7>1 (
+ .I0(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add00008 ),
+ .I1(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add000012 ),
+ .I2(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add000010 ),
+ .I3(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add0000_cy<9>_bdd4 ),
+ .O(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/wr_data_count_i_add0000 [7])
+ );
+ LUT3 #(
+ .INIT ( 8'h6C ))
+ \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/wr_data_count_i_add0000<6>1 (
+ .I0(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add00008 ),
+ .I1(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add000010 ),
+ .I2(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add0000_cy<9>_bdd4 ),
+ .O(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/wr_data_count_i_add0000 [6])
+ );
+ LUT2 #(
+ .INIT ( 4'h6 ))
+ \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/wr_data_count_i_add0000<5>1 (
+ .I0(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add00008 ),
+ .I1(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add0000_cy<9>_bdd4 ),
+ .O(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/wr_data_count_i_add0000 [5])
+ );
+ LUT3 #(
+ .INIT ( 8'h82 ))
+ \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/rd_dc_i_mux0002<4>1 (
+ .I0(\BU2/N33 ),
+ .I1(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub00006 ),
+ .I2(\BU2/N38 ),
+ .O(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/rd_dc_i_mux0002 [4])
+ );
+ LUT4 #(
+ .INIT ( 16'h6CCC ))
+ \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add0000_xor<4>11 (
+ .I0(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add00002 ),
+ .I1(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add00006 ),
+ .I2(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add00004 ),
+ .I3(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add0000_cy[1] ),
+ .O(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/wr_data_count_i_add0000 [4])
+ );
+ LUT4 #(
+ .INIT ( 16'h60C0 ))
+ \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/rd_dc_i_mux0002<3>1 (
+ .I0(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub00002 ),
+ .I1(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub00004 ),
+ .I2(\BU2/N33 ),
+ .I3(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub0000_cy [1]),
+ .O(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/rd_dc_i_mux0002 [3])
+ );
+ LUT3 #(
+ .INIT ( 8'h6C ))
+ \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add0000_xor<3>11 (
+ .I0(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add00002 ),
+ .I1(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add00004 ),
+ .I2(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add0000_cy[1] ),
+ .O(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/wr_data_count_i_add0000 [3])
+ );
+ LUT3 #(
+ .INIT ( 8'h28 ))
+ \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/rd_dc_i_mux0002<2>1 (
+ .I0(\BU2/N33 ),
+ .I1(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub00002 ),
+ .I2(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub0000_cy [1]),
+ .O(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/rd_dc_i_mux0002 [2])
+ );
+ LUT2 #(
+ .INIT ( 4'h6 ))
+ \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add0000_xor<2>11 (
+ .I0(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add00002 ),
+ .I1(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add0000_cy[1] ),
+ .O(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/wr_data_count_i_add0000 [2])
+ );
+ LUT2 #(
+ .INIT ( 4'h4 ))
+ \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/rd_dc_i_mux0002<1>1 (
+ .I0(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub0000_cy [1]),
+ .I1(\BU2/N33 ),
+ .O(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/rd_dc_i_mux0002 [1])
+ );
+ LUT4 #(
+ .INIT ( 16'h9669 ))
+ \BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin_xor000611 (
+ .I0(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg_d1 [3]),
+ .I1(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg_d1 [4]),
+ .I2(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg_d1 [5]),
+ .I3(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin_xor0002 ),
+ .O(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin_xor0006_bdd0 )
+ );
+ LUT4 #(
+ .INIT ( 16'h9669 ))
+ \BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin_xor00081 (
+ .I0(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg_d1 [0]),
+ .I1(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg_d1 [1]),
+ .I2(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg_d1 [2]),
+ .I3(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin_xor0006_bdd0 ),
+ .O(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin_xor0008 )
+ );
+ LUT4 #(
+ .INIT ( 16'h9669 ))
+ \BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin_xor000611 (
+ .I0(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg_d1 [3]),
+ .I1(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg_d1 [4]),
+ .I2(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg_d1 [5]),
+ .I3(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin_xor0002 ),
+ .O(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin_xor0006_bdd0 )
+ );
+ LUT4 #(
+ .INIT ( 16'h9669 ))
+ \BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin_xor00081 (
+ .I0(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg_d1 [0]),
+ .I1(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg_d1 [1]),
+ .I2(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg_d1 [2]),
+ .I3(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin_xor0006_bdd0 ),
+ .O(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin_xor0008 )
+ );
+ LUT3 #(
+ .INIT ( 8'h69 ))
+ \BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin_xor00071 (
+ .I0(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg_d1 [1]),
+ .I1(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg_d1 [2]),
+ .I2(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin_xor0006_bdd0 ),
+ .O(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin_xor0007 )
+ );
+ LUT3 #(
+ .INIT ( 8'h69 ))
+ \BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin_xor00071 (
+ .I0(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg_d1 [1]),
+ .I1(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg_d1 [2]),
+ .I2(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin_xor0006_bdd0 ),
+ .O(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin_xor0007 )
+ );
+ LUT2 #(
+ .INIT ( 4'h9 ))
+ \BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin_xor00062 (
+ .I0(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg_d1 [2]),
+ .I1(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin_xor0006_bdd0 ),
+ .O(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin_xor0006 )
+ );
+ LUT2 #(
+ .INIT ( 4'h9 ))
+ \BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin_xor00062 (
+ .I0(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg_d1 [2]),
+ .I1(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin_xor0006_bdd0 ),
+ .O(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin_xor0006 )
+ );
+ LUT4 #(
+ .INIT ( 16'h9009 ))
+ \BU2/U0/grf.rf/gl0.rd/gras.rsts/c0/v1_0_and00001 (
+ .I0(\BU2/U0/grf.rf/gl0.rd/rpntr/count_d1 [1]),
+ .I1(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin [1]),
+ .I2(\BU2/U0/grf.rf/gl0.rd/rpntr/count_d1 [0]),
+ .I3(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin [0]),
+ .O(\BU2/U0/grf.rf/gl0.rd/gras.rsts/c0/v1 [0])
+ );
+ LUT4 #(
+ .INIT ( 16'h9009 ))
+ \BU2/U0/grf.rf/gl0.rd/gras.rsts/c1/v1_0_and00001 (
+ .I0(\BU2/U0/grf.rf/gl0.rd/rpntr/count [1]),
+ .I1(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin [1]),
+ .I2(\BU2/U0/grf.rf/gl0.rd/rpntr/count [0]),
+ .I3(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin [0]),
+ .O(\BU2/U0/grf.rf/gl0.rd/gras.rsts/c1/v1 [0])
+ );
+ LUT4 #(
+ .INIT ( 16'h9009 ))
+ \BU2/U0/grf.rf/gl0.wr/gwas.wsts/c1/v1_0_and00001 (
+ .I0(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d1 [1]),
+ .I1(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin [1]),
+ .I2(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d1 [0]),
+ .I3(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin [0]),
+ .O(\BU2/U0/grf.rf/gl0.wr/gwas.wsts/c1/v1 [0])
+ );
+ LUT4 #(
+ .INIT ( 16'h9009 ))
+ \BU2/U0/grf.rf/gl0.wr/gwas.wsts/c2/v1_0_and00001 (
+ .I0(\BU2/U0/grf.rf/gl0.wr/wpntr/count [1]),
+ .I1(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin [1]),
+ .I2(\BU2/U0/grf.rf/gl0.wr/wpntr/count [0]),
+ .I3(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin [0]),
+ .O(\BU2/U0/grf.rf/gl0.wr/gwas.wsts/c2/v1 [0])
+ );
+ LUT4 #(
+ .INIT ( 16'hBAAA ))
+ \BU2/U0/grf.rf/gl0.wr/gwas.wsts/ram_full_i_or00001 (
+ .I0(\BU2/U0/grf.rf/gl0.wr/gwas.wsts/comp1 ),
+ .I1(\BU2/U0/grf.rf/gl0.wr/gwas.wsts/ram_full_fb_i_94 ),
+ .I2(wr_en),
+ .I3(\BU2/U0/grf.rf/gl0.wr/gwas.wsts/comp2 ),
+ .O(\BU2/U0/grf.rf/gl0.wr/gwas.wsts/ram_full_i_or0000 )
+ );
+ LUT3 #(
+ .INIT ( 8'hF8 ))
+ \BU2/U0/grf.rf/gl0.rd/gras.rsts/ram_empty_fb_i_or00001 (
+ .I0(\BU2/U0/grf.rf/gl0.rd/gras.rsts/comp1 ),
+ .I1(\BU2/U0/grf.rf/ram_rd_en ),
+ .I2(\BU2/U0/grf.rf/gl0.rd/gras.rsts/comp0 ),
+ .O(\BU2/U0/grf.rf/gl0.rd/gras.rsts/ram_empty_fb_i_or0000 )
+ );
+ LUT4 #(
+ .INIT ( 16'h9009 ))
+ \BU2/U0/grf.rf/gl0.rd/gras.rsts/c0/v1_1_and00001 (
+ .I0(\BU2/U0/grf.rf/gl0.rd/rpntr/count_d1 [3]),
+ .I1(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin [3]),
+ .I2(\BU2/U0/grf.rf/gl0.rd/rpntr/count_d1 [2]),
+ .I3(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin [2]),
+ .O(\BU2/U0/grf.rf/gl0.rd/gras.rsts/c0/v1 [1])
+ );
+ LUT4 #(
+ .INIT ( 16'h9009 ))
+ \BU2/U0/grf.rf/gl0.rd/gras.rsts/c1/v1_1_and00001 (
+ .I0(\BU2/U0/grf.rf/gl0.rd/rpntr/count [3]),
+ .I1(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin [3]),
+ .I2(\BU2/U0/grf.rf/gl0.rd/rpntr/count [2]),
+ .I3(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin [2]),
+ .O(\BU2/U0/grf.rf/gl0.rd/gras.rsts/c1/v1 [1])
+ );
+ LUT4 #(
+ .INIT ( 16'h9009 ))
+ \BU2/U0/grf.rf/gl0.wr/gwas.wsts/c1/v1_1_and00001 (
+ .I0(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d1 [3]),
+ .I1(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin [3]),
+ .I2(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d1 [2]),
+ .I3(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin [2]),
+ .O(\BU2/U0/grf.rf/gl0.wr/gwas.wsts/c1/v1 [1])
+ );
+ LUT4 #(
+ .INIT ( 16'h9009 ))
+ \BU2/U0/grf.rf/gl0.wr/gwas.wsts/c2/v1_1_and00001 (
+ .I0(\BU2/U0/grf.rf/gl0.wr/wpntr/count [3]),
+ .I1(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin [3]),
+ .I2(\BU2/U0/grf.rf/gl0.wr/wpntr/count [2]),
+ .I3(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin [2]),
+ .O(\BU2/U0/grf.rf/gl0.wr/gwas.wsts/c2/v1 [1])
+ );
+ LUT4 #(
+ .INIT ( 16'h9009 ))
+ \BU2/U0/grf.rf/gl0.rd/gras.rsts/c0/v1_2_and00001 (
+ .I0(\BU2/U0/grf.rf/gl0.rd/rpntr/count_d1 [5]),
+ .I1(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin [5]),
+ .I2(\BU2/U0/grf.rf/gl0.rd/rpntr/count_d1 [4]),
+ .I3(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin [4]),
+ .O(\BU2/U0/grf.rf/gl0.rd/gras.rsts/c0/v1 [2])
+ );
+ LUT4 #(
+ .INIT ( 16'h9009 ))
+ \BU2/U0/grf.rf/gl0.rd/gras.rsts/c1/v1_2_and00001 (
+ .I0(\BU2/U0/grf.rf/gl0.rd/rpntr/count [5]),
+ .I1(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin [5]),
+ .I2(\BU2/U0/grf.rf/gl0.rd/rpntr/count [4]),
+ .I3(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin [4]),
+ .O(\BU2/U0/grf.rf/gl0.rd/gras.rsts/c1/v1 [2])
+ );
+ LUT4 #(
+ .INIT ( 16'h9009 ))
+ \BU2/U0/grf.rf/gl0.wr/gwas.wsts/c1/v1_2_and00001 (
+ .I0(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d1 [5]),
+ .I1(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin [5]),
+ .I2(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d1 [4]),
+ .I3(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin [4]),
+ .O(\BU2/U0/grf.rf/gl0.wr/gwas.wsts/c1/v1 [2])
+ );
+ LUT4 #(
+ .INIT ( 16'h9009 ))
+ \BU2/U0/grf.rf/gl0.wr/gwas.wsts/c2/v1_2_and00001 (
+ .I0(\BU2/U0/grf.rf/gl0.wr/wpntr/count [5]),
+ .I1(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin [5]),
+ .I2(\BU2/U0/grf.rf/gl0.wr/wpntr/count [4]),
+ .I3(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin [4]),
+ .O(\BU2/U0/grf.rf/gl0.wr/gwas.wsts/c2/v1 [2])
+ );
+ LUT4 #(
+ .INIT ( 16'h3010 ))
+ \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/rd_dc_i_mux0002<0>1 (
+ .I0(\BU2/N351 ),
+ .I1(\BU2/U0/grf.rf/rstblk/rd_rst_reg [2]),
+ .I2(\BU2/U0/grf.rf/gl0.rd/gr1.rfwft/user_valid_383 ),
+ .I3(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/diff_wr_rd_tmp [0]),
+ .O(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/rd_dc_i_mux0002 [0])
+ );
+ LUT4 #(
+ .INIT ( 16'h9009 ))
+ \BU2/U0/grf.rf/gl0.rd/gras.rsts/c0/v1_3_and00001 (
+ .I0(\BU2/U0/grf.rf/gl0.rd/rpntr/count_d1 [7]),
+ .I1(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin [7]),
+ .I2(\BU2/U0/grf.rf/gl0.rd/rpntr/count_d1 [6]),
+ .I3(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin [6]),
+ .O(\BU2/U0/grf.rf/gl0.rd/gras.rsts/c0/v1 [3])
+ );
+ LUT4 #(
+ .INIT ( 16'h9009 ))
+ \BU2/U0/grf.rf/gl0.rd/gras.rsts/c1/v1_3_and00001 (
+ .I0(\BU2/U0/grf.rf/gl0.rd/rpntr/count [7]),
+ .I1(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin [7]),
+ .I2(\BU2/U0/grf.rf/gl0.rd/rpntr/count [6]),
+ .I3(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin [6]),
+ .O(\BU2/U0/grf.rf/gl0.rd/gras.rsts/c1/v1 [3])
+ );
+ LUT4 #(
+ .INIT ( 16'h9009 ))
+ \BU2/U0/grf.rf/gl0.wr/gwas.wsts/c1/v1_3_and00001 (
+ .I0(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d1 [7]),
+ .I1(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin [7]),
+ .I2(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d1 [6]),
+ .I3(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin [6]),
+ .O(\BU2/U0/grf.rf/gl0.wr/gwas.wsts/c1/v1 [3])
+ );
+ LUT4 #(
+ .INIT ( 16'h9009 ))
+ \BU2/U0/grf.rf/gl0.wr/gwas.wsts/c2/v1_3_and00001 (
+ .I0(\BU2/U0/grf.rf/gl0.wr/wpntr/count [7]),
+ .I1(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin [7]),
+ .I2(\BU2/U0/grf.rf/gl0.wr/wpntr/count [6]),
+ .I3(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin [6]),
+ .O(\BU2/U0/grf.rf/gl0.wr/gwas.wsts/c2/v1 [3])
+ );
+ LUT4 #(
+ .INIT ( 16'h9009 ))
+ \BU2/U0/grf.rf/gl0.rd/gras.rsts/c0/v1_4_and00001 (
+ .I0(\BU2/U0/grf.rf/gl0.rd/rpntr/count_d1 [9]),
+ .I1(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin [9]),
+ .I2(\BU2/U0/grf.rf/gl0.rd/rpntr/count_d1 [8]),
+ .I3(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin [8]),
+ .O(\BU2/U0/grf.rf/gl0.rd/gras.rsts/c0/v1 [4])
+ );
+ LUT4 #(
+ .INIT ( 16'h9009 ))
+ \BU2/U0/grf.rf/gl0.rd/gras.rsts/c1/v1_4_and00001 (
+ .I0(\BU2/U0/grf.rf/gl0.rd/rpntr/count [9]),
+ .I1(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin [9]),
+ .I2(\BU2/U0/grf.rf/gl0.rd/rpntr/count [8]),
+ .I3(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin [8]),
+ .O(\BU2/U0/grf.rf/gl0.rd/gras.rsts/c1/v1 [4])
+ );
+ LUT4 #(
+ .INIT ( 16'h9009 ))
+ \BU2/U0/grf.rf/gl0.wr/gwas.wsts/c1/v1_4_and00001 (
+ .I0(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d1 [9]),
+ .I1(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin [9]),
+ .I2(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d1 [8]),
+ .I3(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin [8]),
+ .O(\BU2/U0/grf.rf/gl0.wr/gwas.wsts/c1/v1 [4])
+ );
+ LUT4 #(
+ .INIT ( 16'h9009 ))
+ \BU2/U0/grf.rf/gl0.wr/gwas.wsts/c2/v1_4_and00001 (
+ .I0(\BU2/U0/grf.rf/gl0.wr/wpntr/count [9]),
+ .I1(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin [9]),
+ .I2(\BU2/U0/grf.rf/gl0.wr/wpntr/count [8]),
+ .I3(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin [8]),
+ .O(\BU2/U0/grf.rf/gl0.wr/gwas.wsts/c2/v1 [4])
+ );
+ LUT2 #(
+ .INIT ( 4'hE ))
+ \BU2/U0/grf.rf/mem/tmp_ram_rd_en1 (
+ .I0(\BU2/U0/grf.rf/ram_rd_en ),
+ .I1(\BU2/U0/grf.rf/rstblk/rd_rst_reg [0]),
+ .O(\BU2/U0/grf.rf/mem/tmp_ram_rd_en )
+ );
+ LUT4 #(
+ .INIT ( 16'h5455 ))
+ \BU2/U0/grf.rf/gl0.rd/gr1.rfwft/RAM_RD_EN_FWFT1 (
+ .I0(\BU2/U0/grf.rf/gl0.rd/gras.rsts/ram_empty_fb_i_81 ),
+ .I1(\BU2/U0/grf.rf/gl0.rd/gr1.rfwft/curr_fwft_state_FSM_FFd2_380 ),
+ .I2(rd_en),
+ .I3(\BU2/U0/grf.rf/gl0.rd/gr1.rfwft/curr_fwft_state_FSM_FFd1_382 ),
+ .O(\BU2/U0/grf.rf/ram_rd_en )
+ );
+ LUT4 #(
+ .INIT ( 16'h6996 ))
+ \BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin_xor00051 (
+ .I0(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg_d1 [4]),
+ .I1(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg_d1 [3]),
+ .I2(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin_xor0002 ),
+ .I3(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg_d1 [5]),
+ .O(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin_xor0005 )
+ );
+ LUT4 #(
+ .INIT ( 16'h6996 ))
+ \BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin_xor00051 (
+ .I0(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg_d1 [4]),
+ .I1(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg_d1 [3]),
+ .I2(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin_xor0002 ),
+ .I3(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg_d1 [5]),
+ .O(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin_xor0005 )
+ );
+ LUT3 #(
+ .INIT ( 8'h96 ))
+ \BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin_xor00041 (
+ .I0(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin_xor0002 ),
+ .I1(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg_d1 [5]),
+ .I2(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg_d1 [4]),
+ .O(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin_xor0004 )
+ );
+ LUT3 #(
+ .INIT ( 8'h96 ))
+ \BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin_xor00041 (
+ .I0(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin_xor0002 ),
+ .I1(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg_d1 [5]),
+ .I2(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg_d1 [4]),
+ .O(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin_xor0004 )
+ );
+ LUT2 #(
+ .INIT ( 4'h6 ))
+ \BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin_xor00032 (
+ .I0(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg_d1 [5]),
+ .I1(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin_xor0002 ),
+ .O(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin_xor0003 )
+ );
+ LUT2 #(
+ .INIT ( 4'h6 ))
+ \BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin_xor00032 (
+ .I0(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg_d1 [5]),
+ .I1(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin_xor0002 ),
+ .O(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin_xor0003 )
+ );
+ LUT3 #(
+ .INIT ( 8'h62 ))
+ \BU2/U0/grf.rf/gl0.rd/gr1.rfwft/RAM_REGOUT_EN1 (
+ .I0(\BU2/U0/grf.rf/gl0.rd/gr1.rfwft/curr_fwft_state_FSM_FFd2_380 ),
+ .I1(\BU2/U0/grf.rf/gl0.rd/gr1.rfwft/curr_fwft_state_FSM_FFd1_382 ),
+ .I2(rd_en),
+ .O(\BU2/U0/grf.rf/ram_regout_en )
+ );
+ LUT2 #(
+ .INIT ( 4'h4 ))
+ \BU2/U0/grf.rf/gl0.wr/ram_wr_en_i1 (
+ .I0(\BU2/U0/grf.rf/gl0.wr/gwas.wsts/ram_full_fb_i_94 ),
+ .I1(wr_en),
+ .O(\BU2/U0/grf.rf/ram_wr_en )
+ );
+ LUT4 #(
+ .INIT ( 16'h69A1 ))
+ \BU2/U0/grf.rf/gl0.rd/gr1.rfwft/curr_fwft_state_FSM_FFd2-In11 (
+ .I0(\BU2/U0/grf.rf/gl0.rd/gras.rsts/ram_empty_fb_i_81 ),
+ .I1(\BU2/U0/grf.rf/gl0.rd/gr1.rfwft/curr_fwft_state_FSM_FFd1_382 ),
+ .I2(\BU2/U0/grf.rf/gl0.rd/gr1.rfwft/curr_fwft_state_FSM_FFd2_380 ),
+ .I3(rd_en),
+ .O(\BU2/U0/grf.rf/gl0.rd/gr1.rfwft/curr_fwft_state_FSM_FFd2-In )
+ );
+ LUT4 #(
+ .INIT ( 16'hCA8A ))
+ \BU2/U0/grf.rf/gl0.rd/gr1.rfwft/empty_fwft_i_or00001 (
+ .I0(\BU2/U0/grf.rf/gl0.rd/gr1.rfwft/empty_fwft_fb_385 ),
+ .I1(\BU2/U0/grf.rf/gl0.rd/gr1.rfwft/curr_fwft_state_FSM_FFd1_382 ),
+ .I2(\BU2/U0/grf.rf/gl0.rd/gr1.rfwft/curr_fwft_state_FSM_FFd2_380 ),
+ .I3(rd_en),
+ .O(\BU2/U0/grf.rf/gl0.rd/gr1.rfwft/empty_fwft_i_or0000 )
+ );
+ LUT4 #(
+ .INIT ( 16'h6996 ))
+ \BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin_xor00021 (
+ .I0(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg_d1 [7]),
+ .I1(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg_d1 [6]),
+ .I2(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg_d1 [9]),
+ .I3(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg_d1 [8]),
+ .O(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin_xor0002 )
+ );
+ LUT4 #(
+ .INIT ( 16'h6996 ))
+ \BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin_xor00021 (
+ .I0(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg_d1 [7]),
+ .I1(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg_d1 [6]),
+ .I2(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg_d1 [9]),
+ .I3(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg_d1 [8]),
+ .O(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin_xor0002 )
+ );
+ LUT3 #(
+ .INIT ( 8'h6E ))
+ \BU2/U0/grf.rf/gl0.rd/gr1.rfwft/curr_fwft_state_FSM_FFd1-In11 (
+ .I0(\BU2/U0/grf.rf/gl0.rd/gr1.rfwft/curr_fwft_state_FSM_FFd1_382 ),
+ .I1(\BU2/U0/grf.rf/gl0.rd/gr1.rfwft/curr_fwft_state_FSM_FFd2_380 ),
+ .I2(rd_en),
+ .O(\BU2/U0/grf.rf/gl0.rd/gr1.rfwft/curr_fwft_state_FSM_FFd1-In )
+ );
+ LUT3 #(
+ .INIT ( 8'h96 ))
+ \BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin_xor00011 (
+ .I0(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg_d1 [9]),
+ .I1(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg_d1 [8]),
+ .I2(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg_d1 [7]),
+ .O(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin_xor0001 )
+ );
+ LUT3 #(
+ .INIT ( 8'h96 ))
+ \BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin_xor00011 (
+ .I0(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg_d1 [9]),
+ .I1(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg_d1 [8]),
+ .I2(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg_d1 [7]),
+ .O(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin_xor0001 )
+ );
+ LUT2 #(
+ .INIT ( 4'h6 ))
+ \BU2/U0/grf.rf/gcx.clkx/Mxor_rd_pntr_gc_xor0000_Result1 (
+ .I0(\BU2/U0/grf.rf/gl0.rd/rpntr/count_d1 [9]),
+ .I1(\BU2/U0/grf.rf/gl0.rd/rpntr/count_d1 [8]),
+ .O(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_xor0000 )
+ );
+ LUT2 #(
+ .INIT ( 4'h6 ))
+ \BU2/U0/grf.rf/gcx.clkx/Mxor_rd_pntr_gc_xor0001_Result1 (
+ .I0(\BU2/U0/grf.rf/gl0.rd/rpntr/count_d1 [8]),
+ .I1(\BU2/U0/grf.rf/gl0.rd/rpntr/count_d1 [7]),
+ .O(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_xor0001 )
+ );
+ LUT2 #(
+ .INIT ( 4'h6 ))
+ \BU2/U0/grf.rf/gcx.clkx/Mxor_rd_pntr_gc_xor0002_Result1 (
+ .I0(\BU2/U0/grf.rf/gl0.rd/rpntr/count_d1 [7]),
+ .I1(\BU2/U0/grf.rf/gl0.rd/rpntr/count_d1 [6]),
+ .O(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_xor0002 )
+ );
+ LUT2 #(
+ .INIT ( 4'h6 ))
+ \BU2/U0/grf.rf/gcx.clkx/Mxor_rd_pntr_gc_xor0003_Result1 (
+ .I0(\BU2/U0/grf.rf/gl0.rd/rpntr/count_d1 [6]),
+ .I1(\BU2/U0/grf.rf/gl0.rd/rpntr/count_d1 [5]),
+ .O(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_xor0003 )
+ );
+ LUT2 #(
+ .INIT ( 4'h6 ))
+ \BU2/U0/grf.rf/gcx.clkx/Mxor_rd_pntr_gc_xor0004_Result1 (
+ .I0(\BU2/U0/grf.rf/gl0.rd/rpntr/count_d1 [5]),
+ .I1(\BU2/U0/grf.rf/gl0.rd/rpntr/count_d1 [4]),
+ .O(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_xor0004 )
+ );
+ LUT2 #(
+ .INIT ( 4'h6 ))
+ \BU2/U0/grf.rf/gcx.clkx/Mxor_rd_pntr_gc_xor0005_Result1 (
+ .I0(\BU2/U0/grf.rf/gl0.rd/rpntr/count_d1 [4]),
+ .I1(\BU2/U0/grf.rf/gl0.rd/rpntr/count_d1 [3]),
+ .O(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_xor0005 )
+ );
+ LUT2 #(
+ .INIT ( 4'h6 ))
+ \BU2/U0/grf.rf/gcx.clkx/Mxor_rd_pntr_gc_xor0006_Result1 (
+ .I0(\BU2/U0/grf.rf/gl0.rd/rpntr/count_d1 [3]),
+ .I1(\BU2/U0/grf.rf/gl0.rd/rpntr/count_d1 [2]),
+ .O(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_xor0006 )
+ );
+ LUT2 #(
+ .INIT ( 4'h6 ))
+ \BU2/U0/grf.rf/gcx.clkx/Mxor_rd_pntr_gc_xor0007_Result1 (
+ .I0(\BU2/U0/grf.rf/gl0.rd/rpntr/count_d1 [2]),
+ .I1(\BU2/U0/grf.rf/gl0.rd/rpntr/count_d1 [1]),
+ .O(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_xor0007 )
+ );
+ LUT2 #(
+ .INIT ( 4'h6 ))
+ \BU2/U0/grf.rf/gcx.clkx/Mxor_rd_pntr_gc_xor0008_Result1 (
+ .I0(\BU2/U0/grf.rf/gl0.rd/rpntr/count_d1 [1]),
+ .I1(\BU2/U0/grf.rf/gl0.rd/rpntr/count_d1 [0]),
+ .O(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_xor0008 )
+ );
+ LUT2 #(
+ .INIT ( 4'h6 ))
+ \BU2/U0/grf.rf/gcx.clkx/Mxor_wr_pntr_gc_xor0000_Result1 (
+ .I0(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d2 [9]),
+ .I1(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d2 [8]),
+ .O(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_xor0000 )
+ );
+ LUT2 #(
+ .INIT ( 4'h6 ))
+ \BU2/U0/grf.rf/gcx.clkx/Mxor_wr_pntr_gc_xor0001_Result1 (
+ .I0(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d2 [8]),
+ .I1(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d2 [7]),
+ .O(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_xor0001 )
+ );
+ LUT2 #(
+ .INIT ( 4'h6 ))
+ \BU2/U0/grf.rf/gcx.clkx/Mxor_wr_pntr_gc_xor0002_Result1 (
+ .I0(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d2 [7]),
+ .I1(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d2 [6]),
+ .O(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_xor0002 )
+ );
+ LUT2 #(
+ .INIT ( 4'h6 ))
+ \BU2/U0/grf.rf/gcx.clkx/Mxor_wr_pntr_gc_xor0003_Result1 (
+ .I0(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d2 [6]),
+ .I1(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d2 [5]),
+ .O(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_xor0003 )
+ );
+ LUT2 #(
+ .INIT ( 4'h6 ))
+ \BU2/U0/grf.rf/gcx.clkx/Mxor_wr_pntr_gc_xor0004_Result1 (
+ .I0(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d2 [5]),
+ .I1(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d2 [4]),
+ .O(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_xor0004 )
+ );
+ LUT2 #(
+ .INIT ( 4'h6 ))
+ \BU2/U0/grf.rf/gcx.clkx/Mxor_wr_pntr_gc_xor0005_Result1 (
+ .I0(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d2 [4]),
+ .I1(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d2 [3]),
+ .O(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_xor0005 )
+ );
+ LUT2 #(
+ .INIT ( 4'h6 ))
+ \BU2/U0/grf.rf/gcx.clkx/Mxor_wr_pntr_gc_xor0006_Result1 (
+ .I0(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d2 [3]),
+ .I1(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d2 [2]),
+ .O(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_xor0006 )
+ );
+ LUT2 #(
+ .INIT ( 4'h6 ))
+ \BU2/U0/grf.rf/gcx.clkx/Mxor_wr_pntr_gc_xor0007_Result1 (
+ .I0(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d2 [2]),
+ .I1(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d2 [1]),
+ .O(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_xor0007 )
+ );
+ LUT2 #(
+ .INIT ( 4'h6 ))
+ \BU2/U0/grf.rf/gcx.clkx/Mxor_wr_pntr_gc_xor0008_Result1 (
+ .I0(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d2 [1]),
+ .I1(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d2 [0]),
+ .O(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_xor0008 )
+ );
+ LUT2 #(
+ .INIT ( 4'h6 ))
+ \BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin_xor00001 (
+ .I0(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg_d1 [8]),
+ .I1(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg_d1 [9]),
+ .O(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin_xor0000 )
+ );
+ LUT2 #(
+ .INIT ( 4'h6 ))
+ \BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin_xor00001 (
+ .I0(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg_d1 [8]),
+ .I1(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg_d1 [9]),
+ .O(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin_xor0000 )
+ );
+ LUT2 #(
+ .INIT ( 4'h4 ))
+ \BU2/U0/grf.rf/rstblk/rd_rst_comb1 (
+ .I0(\BU2/U0/grf.rf/rstblk/rd_rst_asreg_d2_68 ),
+ .I1(\BU2/U0/grf.rf/rstblk/rd_rst_asreg_71 ),
+ .O(\BU2/U0/grf.rf/rstblk/rd_rst_comb )
+ );
+ LUT2 #(
+ .INIT ( 4'h4 ))
+ \BU2/U0/grf.rf/rstblk/wr_rst_comb1 (
+ .I0(\BU2/U0/grf.rf/rstblk/wr_rst_asreg_d2_70 ),
+ .I1(\BU2/U0/grf.rf/rstblk/wr_rst_asreg_72 ),
+ .O(\BU2/U0/grf.rf/rstblk/wr_rst_comb )
+ );
+ FDCE #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/mem/dout_i_0 (
+ .C(rd_clk),
+ .CE(\BU2/U0/grf.rf/ram_regout_en ),
+ .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [0]),
+ .D(\BU2/U0/grf.rf/mem/dout_mem [0]),
+ .Q(dout_3[0])
+ );
+ FDCE #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/mem/dout_i_1 (
+ .C(rd_clk),
+ .CE(\BU2/U0/grf.rf/ram_regout_en ),
+ .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [0]),
+ .D(\BU2/U0/grf.rf/mem/dout_mem [1]),
+ .Q(dout_3[1])
+ );
+ FDCE #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/mem/dout_i_2 (
+ .C(rd_clk),
+ .CE(\BU2/U0/grf.rf/ram_regout_en ),
+ .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [0]),
+ .D(\BU2/U0/grf.rf/mem/dout_mem [2]),
+ .Q(dout_3[2])
+ );
+ FDCE #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/mem/dout_i_3 (
+ .C(rd_clk),
+ .CE(\BU2/U0/grf.rf/ram_regout_en ),
+ .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [0]),
+ .D(\BU2/U0/grf.rf/mem/dout_mem [3]),
+ .Q(dout_3[3])
+ );
+ FDCE #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/mem/dout_i_4 (
+ .C(rd_clk),
+ .CE(\BU2/U0/grf.rf/ram_regout_en ),
+ .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [0]),
+ .D(\BU2/U0/grf.rf/mem/dout_mem [4]),
+ .Q(dout_3[4])
+ );
+ FDCE #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/mem/dout_i_5 (
+ .C(rd_clk),
+ .CE(\BU2/U0/grf.rf/ram_regout_en ),
+ .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [0]),
+ .D(\BU2/U0/grf.rf/mem/dout_mem [5]),
+ .Q(dout_3[5])
+ );
+ FDCE #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/mem/dout_i_6 (
+ .C(rd_clk),
+ .CE(\BU2/U0/grf.rf/ram_regout_en ),
+ .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [0]),
+ .D(\BU2/U0/grf.rf/mem/dout_mem [6]),
+ .Q(dout_3[6])
+ );
+ FDCE #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/mem/dout_i_7 (
+ .C(rd_clk),
+ .CE(\BU2/U0/grf.rf/ram_regout_en ),
+ .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [0]),
+ .D(\BU2/U0/grf.rf/mem/dout_mem [7]),
+ .Q(dout_3[7])
+ );
+ FDCE #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/mem/dout_i_8 (
+ .C(rd_clk),
+ .CE(\BU2/U0/grf.rf/ram_regout_en ),
+ .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [0]),
+ .D(\BU2/U0/grf.rf/mem/dout_mem [8]),
+ .Q(dout_3[8])
+ );
+ FDCE #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/mem/dout_i_9 (
+ .C(rd_clk),
+ .CE(\BU2/U0/grf.rf/ram_regout_en ),
+ .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [0]),
+ .D(\BU2/U0/grf.rf/mem/dout_mem [9]),
+ .Q(dout_3[9])
+ );
+ FDCE #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/mem/dout_i_10 (
+ .C(rd_clk),
+ .CE(\BU2/U0/grf.rf/ram_regout_en ),
+ .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [0]),
+ .D(\BU2/U0/grf.rf/mem/dout_mem [10]),
+ .Q(dout_3[10])
+ );
+ FDCE #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/mem/dout_i_11 (
+ .C(rd_clk),
+ .CE(\BU2/U0/grf.rf/ram_regout_en ),
+ .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [0]),
+ .D(\BU2/U0/grf.rf/mem/dout_mem [11]),
+ .Q(dout_3[11])
+ );
+ FDCE #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/mem/dout_i_12 (
+ .C(rd_clk),
+ .CE(\BU2/U0/grf.rf/ram_regout_en ),
+ .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [0]),
+ .D(\BU2/U0/grf.rf/mem/dout_mem [12]),
+ .Q(dout_3[12])
+ );
+ FDCE #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/mem/dout_i_13 (
+ .C(rd_clk),
+ .CE(\BU2/U0/grf.rf/ram_regout_en ),
+ .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [0]),
+ .D(\BU2/U0/grf.rf/mem/dout_mem [13]),
+ .Q(dout_3[13])
+ );
+ FDCE #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/mem/dout_i_14 (
+ .C(rd_clk),
+ .CE(\BU2/U0/grf.rf/ram_regout_en ),
+ .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [0]),
+ .D(\BU2/U0/grf.rf/mem/dout_mem [14]),
+ .Q(dout_3[14])
+ );
+ FDCE #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/mem/dout_i_15 (
+ .C(rd_clk),
+ .CE(\BU2/U0/grf.rf/ram_regout_en ),
+ .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [0]),
+ .D(\BU2/U0/grf.rf/mem/dout_mem [15]),
+ .Q(dout_3[15])
+ );
+ FDCE #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/mem/dout_i_16 (
+ .C(rd_clk),
+ .CE(\BU2/U0/grf.rf/ram_regout_en ),
+ .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [0]),
+ .D(\BU2/U0/grf.rf/mem/dout_mem [16]),
+ .Q(dout_3[16])
+ );
+ FDCE #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/mem/dout_i_17 (
+ .C(rd_clk),
+ .CE(\BU2/U0/grf.rf/ram_regout_en ),
+ .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [0]),
+ .D(\BU2/U0/grf.rf/mem/dout_mem [17]),
+ .Q(dout_3[17])
+ );
+ FDCE #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gl0.wr/wpntr/count_d2_0 (
+ .C(wr_clk),
+ .CE(\BU2/U0/grf.rf/ram_wr_en ),
+ .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [1]),
+ .D(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d1 [0]),
+ .Q(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d2 [0])
+ );
+ FDCE #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gl0.wr/wpntr/count_d2_1 (
+ .C(wr_clk),
+ .CE(\BU2/U0/grf.rf/ram_wr_en ),
+ .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [1]),
+ .D(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d1 [1]),
+ .Q(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d2 [1])
+ );
+ FDCE #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gl0.wr/wpntr/count_d2_2 (
+ .C(wr_clk),
+ .CE(\BU2/U0/grf.rf/ram_wr_en ),
+ .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [1]),
+ .D(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d1 [2]),
+ .Q(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d2 [2])
+ );
+ FDCE #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gl0.wr/wpntr/count_d2_3 (
+ .C(wr_clk),
+ .CE(\BU2/U0/grf.rf/ram_wr_en ),
+ .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [1]),
+ .D(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d1 [3]),
+ .Q(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d2 [3])
+ );
+ FDCE #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gl0.wr/wpntr/count_d2_4 (
+ .C(wr_clk),
+ .CE(\BU2/U0/grf.rf/ram_wr_en ),
+ .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [1]),
+ .D(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d1 [4]),
+ .Q(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d2 [4])
+ );
+ FDCE #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gl0.wr/wpntr/count_d2_5 (
+ .C(wr_clk),
+ .CE(\BU2/U0/grf.rf/ram_wr_en ),
+ .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [1]),
+ .D(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d1 [5]),
+ .Q(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d2 [5])
+ );
+ FDCE #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gl0.wr/wpntr/count_d2_6 (
+ .C(wr_clk),
+ .CE(\BU2/U0/grf.rf/ram_wr_en ),
+ .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [1]),
+ .D(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d1 [6]),
+ .Q(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d2 [6])
+ );
+ FDCE #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gl0.wr/wpntr/count_d2_7 (
+ .C(wr_clk),
+ .CE(\BU2/U0/grf.rf/ram_wr_en ),
+ .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [1]),
+ .D(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d1 [7]),
+ .Q(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d2 [7])
+ );
+ FDCE #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gl0.wr/wpntr/count_d2_8 (
+ .C(wr_clk),
+ .CE(\BU2/U0/grf.rf/ram_wr_en ),
+ .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [1]),
+ .D(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d1 [8]),
+ .Q(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d2 [8])
+ );
+ FDCE #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gl0.wr/wpntr/count_d2_9 (
+ .C(wr_clk),
+ .CE(\BU2/U0/grf.rf/ram_wr_en ),
+ .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [1]),
+ .D(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d1 [9]),
+ .Q(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d2 [9])
+ );
+ FDCE #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gl0.wr/wpntr/count_d1_9 (
+ .C(wr_clk),
+ .CE(\BU2/U0/grf.rf/ram_wr_en ),
+ .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [1]),
+ .D(\BU2/U0/grf.rf/gl0.wr/wpntr/count [9]),
+ .Q(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d1 [9])
+ );
+ FDCE #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gl0.wr/wpntr/count_d1_8 (
+ .C(wr_clk),
+ .CE(\BU2/U0/grf.rf/ram_wr_en ),
+ .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [1]),
+ .D(\BU2/U0/grf.rf/gl0.wr/wpntr/count [8]),
+ .Q(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d1 [8])
+ );
+ FDCE #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gl0.wr/wpntr/count_d1_6 (
+ .C(wr_clk),
+ .CE(\BU2/U0/grf.rf/ram_wr_en ),
+ .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [1]),
+ .D(\BU2/U0/grf.rf/gl0.wr/wpntr/count [6]),
+ .Q(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d1 [6])
+ );
+ FDCE #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gl0.wr/wpntr/count_d1_5 (
+ .C(wr_clk),
+ .CE(\BU2/U0/grf.rf/ram_wr_en ),
+ .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [1]),
+ .D(\BU2/U0/grf.rf/gl0.wr/wpntr/count [5]),
+ .Q(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d1 [5])
+ );
+ FDCE #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gl0.wr/wpntr/count_d1_7 (
+ .C(wr_clk),
+ .CE(\BU2/U0/grf.rf/ram_wr_en ),
+ .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [1]),
+ .D(\BU2/U0/grf.rf/gl0.wr/wpntr/count [7]),
+ .Q(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d1 [7])
+ );
+ FDCE #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gl0.wr/wpntr/count_d1_4 (
+ .C(wr_clk),
+ .CE(\BU2/U0/grf.rf/ram_wr_en ),
+ .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [1]),
+ .D(\BU2/U0/grf.rf/gl0.wr/wpntr/count [4]),
+ .Q(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d1 [4])
+ );
+ FDCE #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gl0.wr/wpntr/count_d1_3 (
+ .C(wr_clk),
+ .CE(\BU2/U0/grf.rf/ram_wr_en ),
+ .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [1]),
+ .D(\BU2/U0/grf.rf/gl0.wr/wpntr/count [3]),
+ .Q(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d1 [3])
+ );
+ FDCE #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gl0.wr/wpntr/count_d1_1 (
+ .C(wr_clk),
+ .CE(\BU2/U0/grf.rf/ram_wr_en ),
+ .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [1]),
+ .D(\BU2/U0/grf.rf/gl0.wr/wpntr/count [1]),
+ .Q(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d1 [1])
+ );
+ FDPE #(
+ .INIT ( 1'b1 ))
+ \BU2/U0/grf.rf/gl0.wr/wpntr/count_d1_0 (
+ .C(wr_clk),
+ .CE(\BU2/U0/grf.rf/ram_wr_en ),
+ .D(\BU2/U0/grf.rf/gl0.wr/wpntr/count [0]),
+ .PRE(\BU2/U0/grf.rf/rstblk/wr_rst_reg [1]),
+ .Q(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d1 [0])
+ );
+ FDCE #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gl0.wr/wpntr/count_d1_2 (
+ .C(wr_clk),
+ .CE(\BU2/U0/grf.rf/ram_wr_en ),
+ .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [1]),
+ .D(\BU2/U0/grf.rf/gl0.wr/wpntr/count [2]),
+ .Q(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d1 [2])
+ );
+ MUXCY \BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy<0> (
+ .CI(\BU2/N1 ),
+ .DI(\BU2/data_count [0]),
+ .S(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy<0>_rt_425 ),
+ .O(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy [0])
+ );
+ XORCY \BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_xor<0> (
+ .CI(\BU2/N1 ),
+ .LI(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy<0>_rt_425 ),
+ .O(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count )
+ );
+ MUXCY \BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy<1> (
+ .CI(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy [0]),
+ .DI(\BU2/data_count [0]),
+ .S(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy<1>_rt_424 ),
+ .O(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy [1])
+ );
+ XORCY \BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_xor<1> (
+ .CI(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy [0]),
+ .LI(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy<1>_rt_424 ),
+ .O(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count1 )
+ );
+ MUXCY \BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy<2> (
+ .CI(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy [1]),
+ .DI(\BU2/data_count [0]),
+ .S(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy<2>_rt_422 ),
+ .O(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy [2])
+ );
+ XORCY \BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_xor<2> (
+ .CI(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy [1]),
+ .LI(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy<2>_rt_422 ),
+ .O(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count2 )
+ );
+ MUXCY \BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy<3> (
+ .CI(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy [2]),
+ .DI(\BU2/data_count [0]),
+ .S(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy<3>_rt_420 ),
+ .O(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy [3])
+ );
+ XORCY \BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_xor<3> (
+ .CI(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy [2]),
+ .LI(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy<3>_rt_420 ),
+ .O(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count3 )
+ );
+ MUXCY \BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy<4> (
+ .CI(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy [3]),
+ .DI(\BU2/data_count [0]),
+ .S(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy<4>_rt_418 ),
+ .O(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy [4])
+ );
+ XORCY \BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_xor<4> (
+ .CI(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy [3]),
+ .LI(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy<4>_rt_418 ),
+ .O(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count4 )
+ );
+ MUXCY \BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy<5> (
+ .CI(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy [4]),
+ .DI(\BU2/data_count [0]),
+ .S(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy<5>_rt_416 ),
+ .O(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy [5])
+ );
+ XORCY \BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_xor<5> (
+ .CI(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy [4]),
+ .LI(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy<5>_rt_416 ),
+ .O(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count5 )
+ );
+ MUXCY \BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy<6> (
+ .CI(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy [5]),
+ .DI(\BU2/data_count [0]),
+ .S(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy<6>_rt_414 ),
+ .O(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy [6])
+ );
+ XORCY \BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_xor<6> (
+ .CI(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy [5]),
+ .LI(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy<6>_rt_414 ),
+ .O(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count6 )
+ );
+ MUXCY \BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy<7> (
+ .CI(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy [6]),
+ .DI(\BU2/data_count [0]),
+ .S(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy<7>_rt_412 ),
+ .O(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy [7])
+ );
+ XORCY \BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_xor<7> (
+ .CI(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy [6]),
+ .LI(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy<7>_rt_412 ),
+ .O(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count7 )
+ );
+ MUXCY \BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy<8> (
+ .CI(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy [7]),
+ .DI(\BU2/data_count [0]),
+ .S(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy<8>_rt_410 ),
+ .O(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy [8])
+ );
+ XORCY \BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_xor<8> (
+ .CI(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy [7]),
+ .LI(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy<8>_rt_410 ),
+ .O(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count8 )
+ );
+ XORCY \BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_xor<9> (
+ .CI(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_cy [8]),
+ .LI(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count_xor<9>_rt_408 ),
+ .O(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count9 )
+ );
+ FDCE #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gl0.wr/wpntr/count_2 (
+ .C(wr_clk),
+ .CE(\BU2/U0/grf.rf/ram_wr_en ),
+ .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [1]),
+ .D(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count2 ),
+ .Q(\BU2/U0/grf.rf/gl0.wr/wpntr/count [2])
+ );
+ FDCE #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gl0.wr/wpntr/count_0 (
+ .C(wr_clk),
+ .CE(\BU2/U0/grf.rf/ram_wr_en ),
+ .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [1]),
+ .D(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count ),
+ .Q(\BU2/U0/grf.rf/gl0.wr/wpntr/count [0])
+ );
+ FDPE #(
+ .INIT ( 1'b1 ))
+ \BU2/U0/grf.rf/gl0.wr/wpntr/count_1 (
+ .C(wr_clk),
+ .CE(\BU2/U0/grf.rf/ram_wr_en ),
+ .D(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count1 ),
+ .PRE(\BU2/U0/grf.rf/rstblk/wr_rst_reg [1]),
+ .Q(\BU2/U0/grf.rf/gl0.wr/wpntr/count [1])
+ );
+ FDCE #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gl0.wr/wpntr/count_3 (
+ .C(wr_clk),
+ .CE(\BU2/U0/grf.rf/ram_wr_en ),
+ .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [1]),
+ .D(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count3 ),
+ .Q(\BU2/U0/grf.rf/gl0.wr/wpntr/count [3])
+ );
+ FDCE #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gl0.wr/wpntr/count_4 (
+ .C(wr_clk),
+ .CE(\BU2/U0/grf.rf/ram_wr_en ),
+ .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [1]),
+ .D(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count4 ),
+ .Q(\BU2/U0/grf.rf/gl0.wr/wpntr/count [4])
+ );
+ FDCE #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gl0.wr/wpntr/count_7 (
+ .C(wr_clk),
+ .CE(\BU2/U0/grf.rf/ram_wr_en ),
+ .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [1]),
+ .D(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count7 ),
+ .Q(\BU2/U0/grf.rf/gl0.wr/wpntr/count [7])
+ );
+ FDCE #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gl0.wr/wpntr/count_5 (
+ .C(wr_clk),
+ .CE(\BU2/U0/grf.rf/ram_wr_en ),
+ .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [1]),
+ .D(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count5 ),
+ .Q(\BU2/U0/grf.rf/gl0.wr/wpntr/count [5])
+ );
+ FDCE #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gl0.wr/wpntr/count_6 (
+ .C(wr_clk),
+ .CE(\BU2/U0/grf.rf/ram_wr_en ),
+ .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [1]),
+ .D(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count6 ),
+ .Q(\BU2/U0/grf.rf/gl0.wr/wpntr/count [6])
+ );
+ FDCE #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gl0.wr/wpntr/count_8 (
+ .C(wr_clk),
+ .CE(\BU2/U0/grf.rf/ram_wr_en ),
+ .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [1]),
+ .D(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count8 ),
+ .Q(\BU2/U0/grf.rf/gl0.wr/wpntr/count [8])
+ );
+ FDCE #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gl0.wr/wpntr/count_9 (
+ .C(wr_clk),
+ .CE(\BU2/U0/grf.rf/ram_wr_en ),
+ .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [1]),
+ .D(\BU2/U0/grf.rf/gl0.wr/wpntr/Mcount_count9 ),
+ .Q(\BU2/U0/grf.rf/gl0.wr/wpntr/count [9])
+ );
+ FDP #(
+ .INIT ( 1'b1 ))
+ \BU2/U0/grf.rf/gl0.rd/gr1.rfwft/empty_fwft_fb (
+ .C(rd_clk),
+ .D(\BU2/U0/grf.rf/gl0.rd/gr1.rfwft/empty_fwft_i_or0000 ),
+ .PRE(\BU2/U0/grf.rf/rstblk/rd_rst_reg [2]),
+ .Q(\BU2/U0/grf.rf/gl0.rd/gr1.rfwft/empty_fwft_fb_385 )
+ );
+ FDP #(
+ .INIT ( 1'b1 ))
+ \BU2/U0/grf.rf/gl0.rd/gr1.rfwft/empty_fwft_i (
+ .C(rd_clk),
+ .D(\BU2/U0/grf.rf/gl0.rd/gr1.rfwft/empty_fwft_i_or0000 ),
+ .PRE(\BU2/U0/grf.rf/rstblk/rd_rst_reg [2]),
+ .Q(empty)
+ );
+ FDC #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gl0.rd/gr1.rfwft/user_valid (
+ .C(rd_clk),
+ .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [2]),
+ .D(\BU2/U0/grf.rf/gl0.rd/gr1.rfwft/curr_fwft_state_FSM_FFd1-In ),
+ .Q(\BU2/U0/grf.rf/gl0.rd/gr1.rfwft/user_valid_383 )
+ );
+ FDC #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gl0.rd/gr1.rfwft/curr_fwft_state_FSM_FFd1 (
+ .C(rd_clk),
+ .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [2]),
+ .D(\BU2/U0/grf.rf/gl0.rd/gr1.rfwft/curr_fwft_state_FSM_FFd1-In ),
+ .Q(\BU2/U0/grf.rf/gl0.rd/gr1.rfwft/curr_fwft_state_FSM_FFd1_382 )
+ );
+ FDC #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gl0.rd/gr1.rfwft/curr_fwft_state_FSM_FFd2 (
+ .C(rd_clk),
+ .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [2]),
+ .D(\BU2/U0/grf.rf/gl0.rd/gr1.rfwft/curr_fwft_state_FSM_FFd2-In ),
+ .Q(\BU2/U0/grf.rf/gl0.rd/gr1.rfwft/curr_fwft_state_FSM_FFd2_380 )
+ );
+ FDCE #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gl0.rd/rpntr/count_d1_0 (
+ .C(rd_clk),
+ .CE(\BU2/U0/grf.rf/ram_rd_en ),
+ .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [2]),
+ .D(\BU2/U0/grf.rf/gl0.rd/rpntr/count [0]),
+ .Q(\BU2/U0/grf.rf/gl0.rd/rpntr/count_d1 [0])
+ );
+ FDCE #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gl0.rd/rpntr/count_d1_1 (
+ .C(rd_clk),
+ .CE(\BU2/U0/grf.rf/ram_rd_en ),
+ .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [2]),
+ .D(\BU2/U0/grf.rf/gl0.rd/rpntr/count [1]),
+ .Q(\BU2/U0/grf.rf/gl0.rd/rpntr/count_d1 [1])
+ );
+ FDCE #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gl0.rd/rpntr/count_d1_2 (
+ .C(rd_clk),
+ .CE(\BU2/U0/grf.rf/ram_rd_en ),
+ .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [2]),
+ .D(\BU2/U0/grf.rf/gl0.rd/rpntr/count [2]),
+ .Q(\BU2/U0/grf.rf/gl0.rd/rpntr/count_d1 [2])
+ );
+ FDCE #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gl0.rd/rpntr/count_d1_3 (
+ .C(rd_clk),
+ .CE(\BU2/U0/grf.rf/ram_rd_en ),
+ .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [2]),
+ .D(\BU2/U0/grf.rf/gl0.rd/rpntr/count [3]),
+ .Q(\BU2/U0/grf.rf/gl0.rd/rpntr/count_d1 [3])
+ );
+ FDCE #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gl0.rd/rpntr/count_d1_4 (
+ .C(rd_clk),
+ .CE(\BU2/U0/grf.rf/ram_rd_en ),
+ .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [2]),
+ .D(\BU2/U0/grf.rf/gl0.rd/rpntr/count [4]),
+ .Q(\BU2/U0/grf.rf/gl0.rd/rpntr/count_d1 [4])
+ );
+ FDCE #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gl0.rd/rpntr/count_d1_5 (
+ .C(rd_clk),
+ .CE(\BU2/U0/grf.rf/ram_rd_en ),
+ .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [2]),
+ .D(\BU2/U0/grf.rf/gl0.rd/rpntr/count [5]),
+ .Q(\BU2/U0/grf.rf/gl0.rd/rpntr/count_d1 [5])
+ );
+ FDCE #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gl0.rd/rpntr/count_d1_6 (
+ .C(rd_clk),
+ .CE(\BU2/U0/grf.rf/ram_rd_en ),
+ .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [2]),
+ .D(\BU2/U0/grf.rf/gl0.rd/rpntr/count [6]),
+ .Q(\BU2/U0/grf.rf/gl0.rd/rpntr/count_d1 [6])
+ );
+ FDCE #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gl0.rd/rpntr/count_d1_7 (
+ .C(rd_clk),
+ .CE(\BU2/U0/grf.rf/ram_rd_en ),
+ .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [2]),
+ .D(\BU2/U0/grf.rf/gl0.rd/rpntr/count [7]),
+ .Q(\BU2/U0/grf.rf/gl0.rd/rpntr/count_d1 [7])
+ );
+ FDCE #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gl0.rd/rpntr/count_d1_8 (
+ .C(rd_clk),
+ .CE(\BU2/U0/grf.rf/ram_rd_en ),
+ .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [2]),
+ .D(\BU2/U0/grf.rf/gl0.rd/rpntr/count [8]),
+ .Q(\BU2/U0/grf.rf/gl0.rd/rpntr/count_d1 [8])
+ );
+ FDCE #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gl0.rd/rpntr/count_d1_9 (
+ .C(rd_clk),
+ .CE(\BU2/U0/grf.rf/ram_rd_en ),
+ .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [2]),
+ .D(\BU2/U0/grf.rf/gl0.rd/rpntr/count [9]),
+ .Q(\BU2/U0/grf.rf/gl0.rd/rpntr/count_d1 [9])
+ );
+ MUXCY \BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy<0> (
+ .CI(\BU2/N1 ),
+ .DI(\BU2/data_count [0]),
+ .S(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy<0>_rt_378 ),
+ .O(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy [0])
+ );
+ XORCY \BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_xor<0> (
+ .CI(\BU2/N1 ),
+ .LI(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy<0>_rt_378 ),
+ .O(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count )
+ );
+ MUXCY \BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy<1> (
+ .CI(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy [0]),
+ .DI(\BU2/data_count [0]),
+ .S(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy<1>_rt_377 ),
+ .O(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy [1])
+ );
+ XORCY \BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_xor<1> (
+ .CI(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy [0]),
+ .LI(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy<1>_rt_377 ),
+ .O(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count1 )
+ );
+ MUXCY \BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy<2> (
+ .CI(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy [1]),
+ .DI(\BU2/data_count [0]),
+ .S(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy<2>_rt_375 ),
+ .O(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy [2])
+ );
+ XORCY \BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_xor<2> (
+ .CI(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy [1]),
+ .LI(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy<2>_rt_375 ),
+ .O(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count2 )
+ );
+ MUXCY \BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy<3> (
+ .CI(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy [2]),
+ .DI(\BU2/data_count [0]),
+ .S(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy<3>_rt_373 ),
+ .O(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy [3])
+ );
+ XORCY \BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_xor<3> (
+ .CI(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy [2]),
+ .LI(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy<3>_rt_373 ),
+ .O(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count3 )
+ );
+ MUXCY \BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy<4> (
+ .CI(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy [3]),
+ .DI(\BU2/data_count [0]),
+ .S(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy<4>_rt_371 ),
+ .O(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy [4])
+ );
+ XORCY \BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_xor<4> (
+ .CI(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy [3]),
+ .LI(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy<4>_rt_371 ),
+ .O(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count4 )
+ );
+ MUXCY \BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy<5> (
+ .CI(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy [4]),
+ .DI(\BU2/data_count [0]),
+ .S(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy<5>_rt_369 ),
+ .O(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy [5])
+ );
+ XORCY \BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_xor<5> (
+ .CI(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy [4]),
+ .LI(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy<5>_rt_369 ),
+ .O(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count5 )
+ );
+ MUXCY \BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy<6> (
+ .CI(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy [5]),
+ .DI(\BU2/data_count [0]),
+ .S(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy<6>_rt_367 ),
+ .O(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy [6])
+ );
+ XORCY \BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_xor<6> (
+ .CI(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy [5]),
+ .LI(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy<6>_rt_367 ),
+ .O(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count6 )
+ );
+ MUXCY \BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy<7> (
+ .CI(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy [6]),
+ .DI(\BU2/data_count [0]),
+ .S(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy<7>_rt_365 ),
+ .O(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy [7])
+ );
+ XORCY \BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_xor<7> (
+ .CI(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy [6]),
+ .LI(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy<7>_rt_365 ),
+ .O(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count7 )
+ );
+ MUXCY \BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy<8> (
+ .CI(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy [7]),
+ .DI(\BU2/data_count [0]),
+ .S(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy<8>_rt_363 ),
+ .O(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy [8])
+ );
+ XORCY \BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_xor<8> (
+ .CI(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy [7]),
+ .LI(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy<8>_rt_363 ),
+ .O(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count8 )
+ );
+ XORCY \BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_xor<9> (
+ .CI(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_cy [8]),
+ .LI(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count_xor<9>_rt_361 ),
+ .O(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count9 )
+ );
+ FDCE #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gl0.rd/rpntr/count_2 (
+ .C(rd_clk),
+ .CE(\BU2/U0/grf.rf/ram_rd_en ),
+ .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [2]),
+ .D(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count2 ),
+ .Q(\BU2/U0/grf.rf/gl0.rd/rpntr/count [2])
+ );
+ FDPE #(
+ .INIT ( 1'b1 ))
+ \BU2/U0/grf.rf/gl0.rd/rpntr/count_0 (
+ .C(rd_clk),
+ .CE(\BU2/U0/grf.rf/ram_rd_en ),
+ .D(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count ),
+ .PRE(\BU2/U0/grf.rf/rstblk/rd_rst_reg [2]),
+ .Q(\BU2/U0/grf.rf/gl0.rd/rpntr/count [0])
+ );
+ FDCE #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gl0.rd/rpntr/count_1 (
+ .C(rd_clk),
+ .CE(\BU2/U0/grf.rf/ram_rd_en ),
+ .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [2]),
+ .D(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count1 ),
+ .Q(\BU2/U0/grf.rf/gl0.rd/rpntr/count [1])
+ );
+ FDCE #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gl0.rd/rpntr/count_3 (
+ .C(rd_clk),
+ .CE(\BU2/U0/grf.rf/ram_rd_en ),
+ .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [2]),
+ .D(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count3 ),
+ .Q(\BU2/U0/grf.rf/gl0.rd/rpntr/count [3])
+ );
+ FDCE #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gl0.rd/rpntr/count_4 (
+ .C(rd_clk),
+ .CE(\BU2/U0/grf.rf/ram_rd_en ),
+ .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [2]),
+ .D(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count4 ),
+ .Q(\BU2/U0/grf.rf/gl0.rd/rpntr/count [4])
+ );
+ FDCE #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gl0.rd/rpntr/count_7 (
+ .C(rd_clk),
+ .CE(\BU2/U0/grf.rf/ram_rd_en ),
+ .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [2]),
+ .D(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count7 ),
+ .Q(\BU2/U0/grf.rf/gl0.rd/rpntr/count [7])
+ );
+ FDCE #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gl0.rd/rpntr/count_5 (
+ .C(rd_clk),
+ .CE(\BU2/U0/grf.rf/ram_rd_en ),
+ .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [2]),
+ .D(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count5 ),
+ .Q(\BU2/U0/grf.rf/gl0.rd/rpntr/count [5])
+ );
+ FDCE #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gl0.rd/rpntr/count_6 (
+ .C(rd_clk),
+ .CE(\BU2/U0/grf.rf/ram_rd_en ),
+ .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [2]),
+ .D(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count6 ),
+ .Q(\BU2/U0/grf.rf/gl0.rd/rpntr/count [6])
+ );
+ FDCE #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gl0.rd/rpntr/count_8 (
+ .C(rd_clk),
+ .CE(\BU2/U0/grf.rf/ram_rd_en ),
+ .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [2]),
+ .D(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count8 ),
+ .Q(\BU2/U0/grf.rf/gl0.rd/rpntr/count [8])
+ );
+ FDCE #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gl0.rd/rpntr/count_9 (
+ .C(rd_clk),
+ .CE(\BU2/U0/grf.rf/ram_rd_en ),
+ .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [2]),
+ .D(\BU2/U0/grf.rf/gl0.rd/rpntr/Mcount_count9 ),
+ .Q(\BU2/U0/grf.rf/gl0.rd/rpntr/count [9])
+ );
+ FDC #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_0 (
+ .C(wr_clk),
+ .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [0]),
+ .D(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_xor0008 ),
+ .Q(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc [0])
+ );
+ FDC #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_1 (
+ .C(wr_clk),
+ .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [0]),
+ .D(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_xor0007 ),
+ .Q(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc [1])
+ );
+ FDC #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_2 (
+ .C(wr_clk),
+ .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [0]),
+ .D(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_xor0006 ),
+ .Q(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc [2])
+ );
+ FDC #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_3 (
+ .C(wr_clk),
+ .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [0]),
+ .D(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_xor0005 ),
+ .Q(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc [3])
+ );
+ FDC #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_4 (
+ .C(wr_clk),
+ .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [0]),
+ .D(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_xor0004 ),
+ .Q(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc [4])
+ );
+ FDC #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_5 (
+ .C(wr_clk),
+ .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [0]),
+ .D(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_xor0003 ),
+ .Q(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc [5])
+ );
+ FDC #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_6 (
+ .C(wr_clk),
+ .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [0]),
+ .D(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_xor0002 ),
+ .Q(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc [6])
+ );
+ FDC #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_7 (
+ .C(wr_clk),
+ .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [0]),
+ .D(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_xor0001 ),
+ .Q(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc [7])
+ );
+ FDC #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_8 (
+ .C(wr_clk),
+ .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [0]),
+ .D(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_xor0000 ),
+ .Q(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc [8])
+ );
+ FDC #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_9 (
+ .C(wr_clk),
+ .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [0]),
+ .D(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d2 [9]),
+ .Q(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc [9])
+ );
+ FDC #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_0 (
+ .C(rd_clk),
+ .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [1]),
+ .D(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_xor0008 ),
+ .Q(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc [0])
+ );
+ FDC #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_1 (
+ .C(rd_clk),
+ .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [1]),
+ .D(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_xor0007 ),
+ .Q(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc [1])
+ );
+ FDC #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_2 (
+ .C(rd_clk),
+ .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [1]),
+ .D(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_xor0006 ),
+ .Q(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc [2])
+ );
+ FDC #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_3 (
+ .C(rd_clk),
+ .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [1]),
+ .D(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_xor0005 ),
+ .Q(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc [3])
+ );
+ FDC #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_4 (
+ .C(rd_clk),
+ .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [1]),
+ .D(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_xor0004 ),
+ .Q(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc [4])
+ );
+ FDC #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_5 (
+ .C(rd_clk),
+ .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [1]),
+ .D(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_xor0003 ),
+ .Q(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc [5])
+ );
+ FDC #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_6 (
+ .C(rd_clk),
+ .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [1]),
+ .D(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_xor0002 ),
+ .Q(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc [6])
+ );
+ FDC #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_7 (
+ .C(rd_clk),
+ .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [1]),
+ .D(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_xor0001 ),
+ .Q(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc [7])
+ );
+ FDC #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_8 (
+ .C(rd_clk),
+ .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [1]),
+ .D(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_xor0000 ),
+ .Q(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc [8])
+ );
+ FDC #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_9 (
+ .C(rd_clk),
+ .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [1]),
+ .D(\BU2/U0/grf.rf/gl0.rd/rpntr/count_d1 [9]),
+ .Q(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc [9])
+ );
+ FDC #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg_0 (
+ .C(wr_clk),
+ .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [0]),
+ .D(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc [0]),
+ .Q(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg [0])
+ );
+ FDC #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg_1 (
+ .C(wr_clk),
+ .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [0]),
+ .D(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc [1]),
+ .Q(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg [1])
+ );
+ FDC #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg_2 (
+ .C(wr_clk),
+ .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [0]),
+ .D(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc [2]),
+ .Q(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg [2])
+ );
+ FDC #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg_3 (
+ .C(wr_clk),
+ .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [0]),
+ .D(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc [3]),
+ .Q(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg [3])
+ );
+ FDC #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg_4 (
+ .C(wr_clk),
+ .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [0]),
+ .D(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc [4]),
+ .Q(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg [4])
+ );
+ FDC #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg_5 (
+ .C(wr_clk),
+ .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [0]),
+ .D(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc [5]),
+ .Q(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg [5])
+ );
+ FDC #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg_6 (
+ .C(wr_clk),
+ .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [0]),
+ .D(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc [6]),
+ .Q(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg [6])
+ );
+ FDC #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg_7 (
+ .C(wr_clk),
+ .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [0]),
+ .D(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc [7]),
+ .Q(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg [7])
+ );
+ FDC #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg_8 (
+ .C(wr_clk),
+ .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [0]),
+ .D(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc [8]),
+ .Q(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg [8])
+ );
+ FDC #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg_9 (
+ .C(wr_clk),
+ .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [0]),
+ .D(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc [9]),
+ .Q(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg [9])
+ );
+ FDC #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg_0 (
+ .C(rd_clk),
+ .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [1]),
+ .D(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc [0]),
+ .Q(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg [0])
+ );
+ FDC #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg_1 (
+ .C(rd_clk),
+ .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [1]),
+ .D(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc [1]),
+ .Q(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg [1])
+ );
+ FDC #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg_2 (
+ .C(rd_clk),
+ .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [1]),
+ .D(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc [2]),
+ .Q(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg [2])
+ );
+ FDC #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg_3 (
+ .C(rd_clk),
+ .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [1]),
+ .D(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc [3]),
+ .Q(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg [3])
+ );
+ FDC #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg_4 (
+ .C(rd_clk),
+ .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [1]),
+ .D(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc [4]),
+ .Q(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg [4])
+ );
+ FDC #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg_5 (
+ .C(rd_clk),
+ .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [1]),
+ .D(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc [5]),
+ .Q(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg [5])
+ );
+ FDC #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg_6 (
+ .C(rd_clk),
+ .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [1]),
+ .D(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc [6]),
+ .Q(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg [6])
+ );
+ FDC #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg_7 (
+ .C(rd_clk),
+ .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [1]),
+ .D(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc [7]),
+ .Q(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg [7])
+ );
+ FDC #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg_8 (
+ .C(rd_clk),
+ .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [1]),
+ .D(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc [8]),
+ .Q(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg [8])
+ );
+ FDC #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg_9 (
+ .C(rd_clk),
+ .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [1]),
+ .D(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc [9]),
+ .Q(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg [9])
+ );
+ FDC #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg_d1_0 (
+ .C(wr_clk),
+ .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [0]),
+ .D(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg [0]),
+ .Q(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg_d1 [0])
+ );
+ FDC #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg_d1_1 (
+ .C(wr_clk),
+ .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [0]),
+ .D(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg [1]),
+ .Q(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg_d1 [1])
+ );
+ FDC #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg_d1_2 (
+ .C(wr_clk),
+ .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [0]),
+ .D(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg [2]),
+ .Q(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg_d1 [2])
+ );
+ FDC #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg_d1_3 (
+ .C(wr_clk),
+ .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [0]),
+ .D(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg [3]),
+ .Q(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg_d1 [3])
+ );
+ FDC #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg_d1_4 (
+ .C(wr_clk),
+ .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [0]),
+ .D(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg [4]),
+ .Q(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg_d1 [4])
+ );
+ FDC #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg_d1_5 (
+ .C(wr_clk),
+ .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [0]),
+ .D(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg [5]),
+ .Q(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg_d1 [5])
+ );
+ FDC #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg_d1_6 (
+ .C(wr_clk),
+ .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [0]),
+ .D(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg [6]),
+ .Q(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg_d1 [6])
+ );
+ FDC #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg_d1_7 (
+ .C(wr_clk),
+ .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [0]),
+ .D(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg [7]),
+ .Q(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg_d1 [7])
+ );
+ FDC #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg_d1_8 (
+ .C(wr_clk),
+ .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [0]),
+ .D(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg [8]),
+ .Q(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg_d1 [8])
+ );
+ FDC #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg_d1_9 (
+ .C(wr_clk),
+ .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [0]),
+ .D(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg [9]),
+ .Q(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg_d1 [9])
+ );
+ FDC #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg_d1_0 (
+ .C(rd_clk),
+ .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [1]),
+ .D(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg [0]),
+ .Q(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg_d1 [0])
+ );
+ FDC #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg_d1_1 (
+ .C(rd_clk),
+ .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [1]),
+ .D(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg [1]),
+ .Q(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg_d1 [1])
+ );
+ FDC #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg_d1_2 (
+ .C(rd_clk),
+ .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [1]),
+ .D(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg [2]),
+ .Q(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg_d1 [2])
+ );
+ FDC #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg_d1_3 (
+ .C(rd_clk),
+ .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [1]),
+ .D(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg [3]),
+ .Q(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg_d1 [3])
+ );
+ FDC #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg_d1_4 (
+ .C(rd_clk),
+ .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [1]),
+ .D(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg [4]),
+ .Q(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg_d1 [4])
+ );
+ FDC #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg_d1_5 (
+ .C(rd_clk),
+ .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [1]),
+ .D(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg [5]),
+ .Q(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg_d1 [5])
+ );
+ FDC #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg_d1_6 (
+ .C(rd_clk),
+ .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [1]),
+ .D(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg [6]),
+ .Q(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg_d1 [6])
+ );
+ FDC #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg_d1_7 (
+ .C(rd_clk),
+ .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [1]),
+ .D(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg [7]),
+ .Q(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg_d1 [7])
+ );
+ FDC #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg_d1_8 (
+ .C(rd_clk),
+ .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [1]),
+ .D(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg [8]),
+ .Q(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg_d1 [8])
+ );
+ FDC #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg_d1_9 (
+ .C(rd_clk),
+ .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [1]),
+ .D(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg [9]),
+ .Q(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg_d1 [9])
+ );
+ FDC #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin_0 (
+ .C(rd_clk),
+ .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [1]),
+ .D(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin_xor0008 ),
+ .Q(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin [0])
+ );
+ FDC #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin_1 (
+ .C(rd_clk),
+ .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [1]),
+ .D(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin_xor0007 ),
+ .Q(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin [1])
+ );
+ FDC #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin_2 (
+ .C(rd_clk),
+ .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [1]),
+ .D(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin_xor0006 ),
+ .Q(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin [2])
+ );
+ FDC #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin_3 (
+ .C(rd_clk),
+ .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [1]),
+ .D(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin_xor0005 ),
+ .Q(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin [3])
+ );
+ FDC #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin_4 (
+ .C(rd_clk),
+ .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [1]),
+ .D(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin_xor0004 ),
+ .Q(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin [4])
+ );
+ FDC #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin_5 (
+ .C(rd_clk),
+ .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [1]),
+ .D(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin_xor0003 ),
+ .Q(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin [5])
+ );
+ FDC #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin_6 (
+ .C(rd_clk),
+ .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [1]),
+ .D(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin_xor0002 ),
+ .Q(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin [6])
+ );
+ FDC #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin_7 (
+ .C(rd_clk),
+ .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [1]),
+ .D(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin_xor0001 ),
+ .Q(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin [7])
+ );
+ FDC #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin_8 (
+ .C(rd_clk),
+ .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [1]),
+ .D(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin_xor0000 ),
+ .Q(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin [8])
+ );
+ FDC #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin_9 (
+ .C(rd_clk),
+ .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [1]),
+ .D(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_gc_asreg_d1 [9]),
+ .Q(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin [9])
+ );
+ FDC #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin_0 (
+ .C(wr_clk),
+ .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [0]),
+ .D(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin_xor0008 ),
+ .Q(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin [0])
+ );
+ FDC #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin_1 (
+ .C(wr_clk),
+ .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [0]),
+ .D(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin_xor0007 ),
+ .Q(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin [1])
+ );
+ FDC #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin_2 (
+ .C(wr_clk),
+ .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [0]),
+ .D(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin_xor0006 ),
+ .Q(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin [2])
+ );
+ FDC #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin_3 (
+ .C(wr_clk),
+ .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [0]),
+ .D(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin_xor0005 ),
+ .Q(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin [3])
+ );
+ FDC #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin_4 (
+ .C(wr_clk),
+ .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [0]),
+ .D(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin_xor0004 ),
+ .Q(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin [4])
+ );
+ FDC #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin_5 (
+ .C(wr_clk),
+ .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [0]),
+ .D(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin_xor0003 ),
+ .Q(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin [5])
+ );
+ FDC #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin_6 (
+ .C(wr_clk),
+ .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [0]),
+ .D(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin_xor0002 ),
+ .Q(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin [6])
+ );
+ FDC #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin_7 (
+ .C(wr_clk),
+ .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [0]),
+ .D(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin_xor0001 ),
+ .Q(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin [7])
+ );
+ FDC #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin_8 (
+ .C(wr_clk),
+ .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [0]),
+ .D(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin_xor0000 ),
+ .Q(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin [8])
+ );
+ FDC #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin_9 (
+ .C(wr_clk),
+ .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [0]),
+ .D(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_gc_asreg_d1 [9]),
+ .Q(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin [9])
+ );
+ MUXCY \BU2/U0/grf.rf/gl0.wr/gwas.wsts/c2/gmux.gm[0].gm1.m1 (
+ .CI(\BU2/N1 ),
+ .DI(\BU2/data_count [0]),
+ .S(\BU2/U0/grf.rf/gl0.wr/gwas.wsts/c2/v1 [0]),
+ .O(\BU2/U0/grf.rf/gl0.wr/gwas.wsts/c2/carrynet [0])
+ );
+ MUXCY \BU2/U0/grf.rf/gl0.wr/gwas.wsts/c2/gmux.gm[1].gms.ms (
+ .CI(\BU2/U0/grf.rf/gl0.wr/gwas.wsts/c2/carrynet [0]),
+ .DI(\BU2/data_count [0]),
+ .S(\BU2/U0/grf.rf/gl0.wr/gwas.wsts/c2/v1 [1]),
+ .O(\BU2/U0/grf.rf/gl0.wr/gwas.wsts/c2/carrynet [1])
+ );
+ MUXCY \BU2/U0/grf.rf/gl0.wr/gwas.wsts/c2/gmux.gm[2].gms.ms (
+ .CI(\BU2/U0/grf.rf/gl0.wr/gwas.wsts/c2/carrynet [1]),
+ .DI(\BU2/data_count [0]),
+ .S(\BU2/U0/grf.rf/gl0.wr/gwas.wsts/c2/v1 [2]),
+ .O(\BU2/U0/grf.rf/gl0.wr/gwas.wsts/c2/carrynet [2])
+ );
+ MUXCY \BU2/U0/grf.rf/gl0.wr/gwas.wsts/c2/gmux.gm[3].gms.ms (
+ .CI(\BU2/U0/grf.rf/gl0.wr/gwas.wsts/c2/carrynet [2]),
+ .DI(\BU2/data_count [0]),
+ .S(\BU2/U0/grf.rf/gl0.wr/gwas.wsts/c2/v1 [3]),
+ .O(\BU2/U0/grf.rf/gl0.wr/gwas.wsts/c2/carrynet [3])
+ );
+ MUXCY \BU2/U0/grf.rf/gl0.wr/gwas.wsts/c2/gmux.gm[4].gms.ms (
+ .CI(\BU2/U0/grf.rf/gl0.wr/gwas.wsts/c2/carrynet [3]),
+ .DI(\BU2/data_count [0]),
+ .S(\BU2/U0/grf.rf/gl0.wr/gwas.wsts/c2/v1 [4]),
+ .O(\BU2/U0/grf.rf/gl0.wr/gwas.wsts/comp2 )
+ );
+ MUXCY \BU2/U0/grf.rf/gl0.wr/gwas.wsts/c1/gmux.gm[0].gm1.m1 (
+ .CI(\BU2/N1 ),
+ .DI(\BU2/data_count [0]),
+ .S(\BU2/U0/grf.rf/gl0.wr/gwas.wsts/c1/v1 [0]),
+ .O(\BU2/U0/grf.rf/gl0.wr/gwas.wsts/c1/carrynet [0])
+ );
+ MUXCY \BU2/U0/grf.rf/gl0.wr/gwas.wsts/c1/gmux.gm[1].gms.ms (
+ .CI(\BU2/U0/grf.rf/gl0.wr/gwas.wsts/c1/carrynet [0]),
+ .DI(\BU2/data_count [0]),
+ .S(\BU2/U0/grf.rf/gl0.wr/gwas.wsts/c1/v1 [1]),
+ .O(\BU2/U0/grf.rf/gl0.wr/gwas.wsts/c1/carrynet [1])
+ );
+ MUXCY \BU2/U0/grf.rf/gl0.wr/gwas.wsts/c1/gmux.gm[2].gms.ms (
+ .CI(\BU2/U0/grf.rf/gl0.wr/gwas.wsts/c1/carrynet [1]),
+ .DI(\BU2/data_count [0]),
+ .S(\BU2/U0/grf.rf/gl0.wr/gwas.wsts/c1/v1 [2]),
+ .O(\BU2/U0/grf.rf/gl0.wr/gwas.wsts/c1/carrynet [2])
+ );
+ MUXCY \BU2/U0/grf.rf/gl0.wr/gwas.wsts/c1/gmux.gm[3].gms.ms (
+ .CI(\BU2/U0/grf.rf/gl0.wr/gwas.wsts/c1/carrynet [2]),
+ .DI(\BU2/data_count [0]),
+ .S(\BU2/U0/grf.rf/gl0.wr/gwas.wsts/c1/v1 [3]),
+ .O(\BU2/U0/grf.rf/gl0.wr/gwas.wsts/c1/carrynet [3])
+ );
+ MUXCY \BU2/U0/grf.rf/gl0.wr/gwas.wsts/c1/gmux.gm[4].gms.ms (
+ .CI(\BU2/U0/grf.rf/gl0.wr/gwas.wsts/c1/carrynet [3]),
+ .DI(\BU2/data_count [0]),
+ .S(\BU2/U0/grf.rf/gl0.wr/gwas.wsts/c1/v1 [4]),
+ .O(\BU2/U0/grf.rf/gl0.wr/gwas.wsts/comp1 )
+ );
+ MUXCY \BU2/U0/grf.rf/gl0.rd/gras.rsts/c1/gmux.gm[0].gm1.m1 (
+ .CI(\BU2/N1 ),
+ .DI(\BU2/data_count [0]),
+ .S(\BU2/U0/grf.rf/gl0.rd/gras.rsts/c1/v1 [0]),
+ .O(\BU2/U0/grf.rf/gl0.rd/gras.rsts/c1/carrynet [0])
+ );
+ MUXCY \BU2/U0/grf.rf/gl0.rd/gras.rsts/c1/gmux.gm[1].gms.ms (
+ .CI(\BU2/U0/grf.rf/gl0.rd/gras.rsts/c1/carrynet [0]),
+ .DI(\BU2/data_count [0]),
+ .S(\BU2/U0/grf.rf/gl0.rd/gras.rsts/c1/v1 [1]),
+ .O(\BU2/U0/grf.rf/gl0.rd/gras.rsts/c1/carrynet [1])
+ );
+ MUXCY \BU2/U0/grf.rf/gl0.rd/gras.rsts/c1/gmux.gm[2].gms.ms (
+ .CI(\BU2/U0/grf.rf/gl0.rd/gras.rsts/c1/carrynet [1]),
+ .DI(\BU2/data_count [0]),
+ .S(\BU2/U0/grf.rf/gl0.rd/gras.rsts/c1/v1 [2]),
+ .O(\BU2/U0/grf.rf/gl0.rd/gras.rsts/c1/carrynet [2])
+ );
+ MUXCY \BU2/U0/grf.rf/gl0.rd/gras.rsts/c1/gmux.gm[3].gms.ms (
+ .CI(\BU2/U0/grf.rf/gl0.rd/gras.rsts/c1/carrynet [2]),
+ .DI(\BU2/data_count [0]),
+ .S(\BU2/U0/grf.rf/gl0.rd/gras.rsts/c1/v1 [3]),
+ .O(\BU2/U0/grf.rf/gl0.rd/gras.rsts/c1/carrynet [3])
+ );
+ MUXCY \BU2/U0/grf.rf/gl0.rd/gras.rsts/c1/gmux.gm[4].gms.ms (
+ .CI(\BU2/U0/grf.rf/gl0.rd/gras.rsts/c1/carrynet [3]),
+ .DI(\BU2/data_count [0]),
+ .S(\BU2/U0/grf.rf/gl0.rd/gras.rsts/c1/v1 [4]),
+ .O(\BU2/U0/grf.rf/gl0.rd/gras.rsts/comp1 )
+ );
+ MUXCY \BU2/U0/grf.rf/gl0.rd/gras.rsts/c0/gmux.gm[0].gm1.m1 (
+ .CI(\BU2/N1 ),
+ .DI(\BU2/data_count [0]),
+ .S(\BU2/U0/grf.rf/gl0.rd/gras.rsts/c0/v1 [0]),
+ .O(\BU2/U0/grf.rf/gl0.rd/gras.rsts/c0/carrynet [0])
+ );
+ MUXCY \BU2/U0/grf.rf/gl0.rd/gras.rsts/c0/gmux.gm[1].gms.ms (
+ .CI(\BU2/U0/grf.rf/gl0.rd/gras.rsts/c0/carrynet [0]),
+ .DI(\BU2/data_count [0]),
+ .S(\BU2/U0/grf.rf/gl0.rd/gras.rsts/c0/v1 [1]),
+ .O(\BU2/U0/grf.rf/gl0.rd/gras.rsts/c0/carrynet [1])
+ );
+ MUXCY \BU2/U0/grf.rf/gl0.rd/gras.rsts/c0/gmux.gm[2].gms.ms (
+ .CI(\BU2/U0/grf.rf/gl0.rd/gras.rsts/c0/carrynet [1]),
+ .DI(\BU2/data_count [0]),
+ .S(\BU2/U0/grf.rf/gl0.rd/gras.rsts/c0/v1 [2]),
+ .O(\BU2/U0/grf.rf/gl0.rd/gras.rsts/c0/carrynet [2])
+ );
+ MUXCY \BU2/U0/grf.rf/gl0.rd/gras.rsts/c0/gmux.gm[3].gms.ms (
+ .CI(\BU2/U0/grf.rf/gl0.rd/gras.rsts/c0/carrynet [2]),
+ .DI(\BU2/data_count [0]),
+ .S(\BU2/U0/grf.rf/gl0.rd/gras.rsts/c0/v1 [3]),
+ .O(\BU2/U0/grf.rf/gl0.rd/gras.rsts/c0/carrynet [3])
+ );
+ MUXCY \BU2/U0/grf.rf/gl0.rd/gras.rsts/c0/gmux.gm[4].gms.ms (
+ .CI(\BU2/U0/grf.rf/gl0.rd/gras.rsts/c0/carrynet [3]),
+ .DI(\BU2/data_count [0]),
+ .S(\BU2/U0/grf.rf/gl0.rd/gras.rsts/c0/v1 [4]),
+ .O(\BU2/U0/grf.rf/gl0.rd/gras.rsts/comp0 )
+ );
+ XORCY \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_xor<9> (
+ .CI(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_cy [8]),
+ .LI(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_lut [9]),
+ .O(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add000016 )
+ );
+ LUT2 #(
+ .INIT ( 4'h9 ))
+ \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_lut<9> (
+ .I0(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d2 [9]),
+ .I1(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin [9]),
+ .O(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_lut [9])
+ );
+ XORCY \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_xor<8> (
+ .CI(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_cy [7]),
+ .LI(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_lut [8]),
+ .O(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add000014 )
+ );
+ MUXCY \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_cy<8> (
+ .CI(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_cy [7]),
+ .DI(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d2 [8]),
+ .S(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_lut [8]),
+ .O(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_cy [8])
+ );
+ LUT2 #(
+ .INIT ( 4'h9 ))
+ \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_lut<8> (
+ .I0(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d2 [8]),
+ .I1(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin [8]),
+ .O(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_lut [8])
+ );
+ XORCY \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_xor<7> (
+ .CI(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_cy [6]),
+ .LI(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_lut [7]),
+ .O(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add000012 )
+ );
+ MUXCY \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_cy<7> (
+ .CI(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_cy [6]),
+ .DI(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d2 [7]),
+ .S(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_lut [7]),
+ .O(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_cy [7])
+ );
+ LUT2 #(
+ .INIT ( 4'h9 ))
+ \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_lut<7> (
+ .I0(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d2 [7]),
+ .I1(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin [7]),
+ .O(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_lut [7])
+ );
+ XORCY \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_xor<6> (
+ .CI(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_cy [5]),
+ .LI(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_lut [6]),
+ .O(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add000010 )
+ );
+ MUXCY \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_cy<6> (
+ .CI(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_cy [5]),
+ .DI(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d2 [6]),
+ .S(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_lut [6]),
+ .O(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_cy [6])
+ );
+ LUT2 #(
+ .INIT ( 4'h9 ))
+ \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_lut<6> (
+ .I0(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d2 [6]),
+ .I1(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin [6]),
+ .O(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_lut [6])
+ );
+ XORCY \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_xor<5> (
+ .CI(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_cy [4]),
+ .LI(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_lut [5]),
+ .O(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add00008 )
+ );
+ MUXCY \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_cy<5> (
+ .CI(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_cy [4]),
+ .DI(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d2 [5]),
+ .S(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_lut [5]),
+ .O(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_cy [5])
+ );
+ LUT2 #(
+ .INIT ( 4'h9 ))
+ \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_lut<5> (
+ .I0(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d2 [5]),
+ .I1(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin [5]),
+ .O(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_lut [5])
+ );
+ XORCY \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_xor<4> (
+ .CI(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_cy [3]),
+ .LI(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_lut [4]),
+ .O(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add00006 )
+ );
+ MUXCY \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_cy<4> (
+ .CI(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_cy [3]),
+ .DI(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d2 [4]),
+ .S(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_lut [4]),
+ .O(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_cy [4])
+ );
+ LUT2 #(
+ .INIT ( 4'h9 ))
+ \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_lut<4> (
+ .I0(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin [4]),
+ .I1(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d2 [4]),
+ .O(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_lut [4])
+ );
+ XORCY \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_xor<3> (
+ .CI(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_cy [2]),
+ .LI(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_lut [3]),
+ .O(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add00004 )
+ );
+ MUXCY \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_cy<3> (
+ .CI(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_cy [2]),
+ .DI(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d2 [3]),
+ .S(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_lut [3]),
+ .O(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_cy [3])
+ );
+ LUT2 #(
+ .INIT ( 4'h9 ))
+ \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_lut<3> (
+ .I0(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin [3]),
+ .I1(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d2 [3]),
+ .O(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_lut [3])
+ );
+ XORCY \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_xor<2> (
+ .CI(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_cy [1]),
+ .LI(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_lut [2]),
+ .O(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add00002 )
+ );
+ MUXCY \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_cy<2> (
+ .CI(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_cy [1]),
+ .DI(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d2 [2]),
+ .S(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_lut [2]),
+ .O(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_cy [2])
+ );
+ LUT2 #(
+ .INIT ( 4'h9 ))
+ \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_lut<2> (
+ .I0(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin [2]),
+ .I1(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d2 [2]),
+ .O(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_lut [2])
+ );
+ XORCY \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_xor<1> (
+ .CI(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_cy [0]),
+ .LI(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_lut [1]),
+ .O(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add0000_cy[1] )
+ );
+ MUXCY \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_cy<1> (
+ .CI(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_cy [0]),
+ .DI(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d2 [1]),
+ .S(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_lut [1]),
+ .O(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_cy [1])
+ );
+ LUT2 #(
+ .INIT ( 4'h9 ))
+ \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_lut<1> (
+ .I0(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin [1]),
+ .I1(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d2 [1]),
+ .O(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_lut [1])
+ );
+ XORCY \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_xor<0> (
+ .CI(\BU2/N1 ),
+ .LI(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_lut [0]),
+ .O(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/diff_wr_rd_tmp [0])
+ );
+ MUXCY \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_cy<0> (
+ .CI(\BU2/N1 ),
+ .DI(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d2 [0]),
+ .S(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_lut [0]),
+ .O(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_cy [0])
+ );
+ LUT2 #(
+ .INIT ( 4'h9 ))
+ \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_lut<0> (
+ .I0(\BU2/U0/grf.rf/gl0.wr/wpntr/count_d2 [0]),
+ .I1(\BU2/U0/grf.rf/gcx.clkx/rd_pntr_bin [0]),
+ .O(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Msub_diff_wr_rd_tmp_lut [0])
+ );
+ XORCY \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_xor<9> (
+ .CI(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_cy [8]),
+ .LI(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_lut [9]),
+ .O(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub000016 )
+ );
+ LUT2 #(
+ .INIT ( 4'h9 ))
+ \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_lut<9> (
+ .I0(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin [9]),
+ .I1(\BU2/U0/grf.rf/gl0.rd/rpntr/count_d1 [9]),
+ .O(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_lut [9])
+ );
+ XORCY \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_xor<8> (
+ .CI(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_cy [7]),
+ .LI(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_lut [8]),
+ .O(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub000014 )
+ );
+ MUXCY \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_cy<8> (
+ .CI(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_cy [7]),
+ .DI(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin [8]),
+ .S(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_lut [8]),
+ .O(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_cy [8])
+ );
+ LUT2 #(
+ .INIT ( 4'h9 ))
+ \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_lut<8> (
+ .I0(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin [8]),
+ .I1(\BU2/U0/grf.rf/gl0.rd/rpntr/count_d1 [8]),
+ .O(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_lut [8])
+ );
+ XORCY \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_xor<7> (
+ .CI(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_cy [6]),
+ .LI(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_lut [7]),
+ .O(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub000012 )
+ );
+ MUXCY \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_cy<7> (
+ .CI(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_cy [6]),
+ .DI(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin [7]),
+ .S(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_lut [7]),
+ .O(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_cy [7])
+ );
+ LUT2 #(
+ .INIT ( 4'h9 ))
+ \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_lut<7> (
+ .I0(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin [7]),
+ .I1(\BU2/U0/grf.rf/gl0.rd/rpntr/count_d1 [7]),
+ .O(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_lut [7])
+ );
+ XORCY \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_xor<6> (
+ .CI(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_cy [5]),
+ .LI(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_lut [6]),
+ .O(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub000010 )
+ );
+ MUXCY \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_cy<6> (
+ .CI(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_cy [5]),
+ .DI(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin [6]),
+ .S(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_lut [6]),
+ .O(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_cy [6])
+ );
+ LUT2 #(
+ .INIT ( 4'h9 ))
+ \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_lut<6> (
+ .I0(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin [6]),
+ .I1(\BU2/U0/grf.rf/gl0.rd/rpntr/count_d1 [6]),
+ .O(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_lut [6])
+ );
+ XORCY \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_xor<5> (
+ .CI(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_cy [4]),
+ .LI(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_lut [5]),
+ .O(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub00008 )
+ );
+ MUXCY \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_cy<5> (
+ .CI(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_cy [4]),
+ .DI(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin [5]),
+ .S(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_lut [5]),
+ .O(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_cy [5])
+ );
+ LUT2 #(
+ .INIT ( 4'h9 ))
+ \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_lut<5> (
+ .I0(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin [5]),
+ .I1(\BU2/U0/grf.rf/gl0.rd/rpntr/count_d1 [5]),
+ .O(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_lut [5])
+ );
+ XORCY \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_xor<4> (
+ .CI(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_cy [3]),
+ .LI(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_lut [4]),
+ .O(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub00006 )
+ );
+ MUXCY \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_cy<4> (
+ .CI(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_cy [3]),
+ .DI(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin [4]),
+ .S(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_lut [4]),
+ .O(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_cy [4])
+ );
+ LUT2 #(
+ .INIT ( 4'h9 ))
+ \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_lut<4> (
+ .I0(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin [4]),
+ .I1(\BU2/U0/grf.rf/gl0.rd/rpntr/count_d1 [4]),
+ .O(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_lut [4])
+ );
+ XORCY \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_xor<3> (
+ .CI(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_cy [2]),
+ .LI(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_lut [3]),
+ .O(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub00004 )
+ );
+ MUXCY \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_cy<3> (
+ .CI(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_cy [2]),
+ .DI(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin [3]),
+ .S(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_lut [3]),
+ .O(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_cy [3])
+ );
+ LUT2 #(
+ .INIT ( 4'h9 ))
+ \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_lut<3> (
+ .I0(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin [3]),
+ .I1(\BU2/U0/grf.rf/gl0.rd/rpntr/count_d1 [3]),
+ .O(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_lut [3])
+ );
+ XORCY \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_xor<2> (
+ .CI(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_cy [1]),
+ .LI(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_lut [2]),
+ .O(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub00002 )
+ );
+ MUXCY \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_cy<2> (
+ .CI(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_cy [1]),
+ .DI(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin [2]),
+ .S(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_lut [2]),
+ .O(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_cy [2])
+ );
+ LUT2 #(
+ .INIT ( 4'h9 ))
+ \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_lut<2> (
+ .I0(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin [2]),
+ .I1(\BU2/U0/grf.rf/gl0.rd/rpntr/count_d1 [2]),
+ .O(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_lut [2])
+ );
+ XORCY \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_xor<1> (
+ .CI(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_cy [0]),
+ .LI(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_lut [1]),
+ .O(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Madd_rd_dc_i_addsub0000_cy [1])
+ );
+ MUXCY \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_cy<1> (
+ .CI(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_cy [0]),
+ .DI(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin [1]),
+ .S(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_lut [1]),
+ .O(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_cy [1])
+ );
+ LUT2 #(
+ .INIT ( 4'h9 ))
+ \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_lut<1> (
+ .I0(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin [1]),
+ .I1(\BU2/U0/grf.rf/gl0.rd/rpntr/count_d1 [1]),
+ .O(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_lut [1])
+ );
+ XORCY \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_xor<0> (
+ .CI(\BU2/N1 ),
+ .LI(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_lut [0]),
+ .O(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/diff_wr_rd_tmp [0])
+ );
+ MUXCY \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_cy<0> (
+ .CI(\BU2/N1 ),
+ .DI(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin [0]),
+ .S(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_lut [0]),
+ .O(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_cy [0])
+ );
+ LUT2 #(
+ .INIT ( 4'h9 ))
+ \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_lut<0> (
+ .I0(\BU2/U0/grf.rf/gcx.clkx/wr_pntr_bin [0]),
+ .I1(\BU2/U0/grf.rf/gl0.rd/rpntr/count_d1 [0]),
+ .O(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/Msub_diff_wr_rd_tmp_lut [0])
+ );
+ FDC #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/wr_data_count_i_10 (
+ .C(wr_clk),
+ .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [1]),
+ .D(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/Madd_wr_data_count_i_add0000_cy[9] ),
+ .Q(wr_data_count_5[10])
+ );
+ FDC #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/wr_data_count_i_9 (
+ .C(wr_clk),
+ .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [1]),
+ .D(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/wr_data_count_i_add0000 [9]),
+ .Q(wr_data_count_5[9])
+ );
+ FDC #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/wr_data_count_i_8 (
+ .C(wr_clk),
+ .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [1]),
+ .D(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/wr_data_count_i_add0000 [8]),
+ .Q(wr_data_count_5[8])
+ );
+ FDC #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/wr_data_count_i_7 (
+ .C(wr_clk),
+ .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [1]),
+ .D(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/wr_data_count_i_add0000 [7]),
+ .Q(wr_data_count_5[7])
+ );
+ FDC #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/wr_data_count_i_6 (
+ .C(wr_clk),
+ .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [1]),
+ .D(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/wr_data_count_i_add0000 [6]),
+ .Q(wr_data_count_5[6])
+ );
+ FDC #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/wr_data_count_i_5 (
+ .C(wr_clk),
+ .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [1]),
+ .D(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/wr_data_count_i_add0000 [5]),
+ .Q(wr_data_count_5[5])
+ );
+ FDC #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/wr_data_count_i_4 (
+ .C(wr_clk),
+ .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [1]),
+ .D(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/wr_data_count_i_add0000 [4]),
+ .Q(wr_data_count_5[4])
+ );
+ FDC #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/wr_data_count_i_3 (
+ .C(wr_clk),
+ .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [1]),
+ .D(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/wr_data_count_i_add0000 [3]),
+ .Q(wr_data_count_5[3])
+ );
+ FDC #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/wr_data_count_i_2 (
+ .C(wr_clk),
+ .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [1]),
+ .D(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/wr_data_count_i_add0000 [2]),
+ .Q(wr_data_count_5[2])
+ );
+ FDC #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/wr_data_count_i_1 (
+ .C(wr_clk),
+ .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [1]),
+ .D(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/wr_data_count_i_add0000 [1]),
+ .Q(wr_data_count_5[1])
+ );
+ FDC #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/wr_data_count_i_0 (
+ .C(wr_clk),
+ .CLR(\BU2/U0/grf.rf/rstblk/wr_rst_reg [1]),
+ .D(\BU2/U0/grf.rf/gl0.wr/gwdc1.wdcext/diff_wr_rd_tmp [0]),
+ .Q(wr_data_count_5[0])
+ );
+ FDP #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gl0.wr/gwas.wsts/ram_full_fb_i (
+ .C(wr_clk),
+ .D(\BU2/U0/grf.rf/gl0.wr/gwas.wsts/ram_full_i_or0000 ),
+ .PRE(\BU2/U0/grf.rf/rstblk/wr_rst_reg [1]),
+ .Q(\BU2/U0/grf.rf/gl0.wr/gwas.wsts/ram_full_fb_i_94 )
+ );
+ FDP #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gl0.wr/gwas.wsts/ram_full_i (
+ .C(wr_clk),
+ .D(\BU2/U0/grf.rf/gl0.wr/gwas.wsts/ram_full_i_or0000 ),
+ .PRE(\BU2/U0/grf.rf/rstblk/wr_rst_reg [1]),
+ .Q(full)
+ );
+ FDCP #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/rd_dc_i_10 (
+ .C(rd_clk),
+ .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [2]),
+ .D(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/rd_dc_i_mux0002 [10]),
+ .PRE(\BU2/data_count [0]),
+ .Q(rd_data_count_4[10])
+ );
+ FDCP #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/rd_dc_i_9 (
+ .C(rd_clk),
+ .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [2]),
+ .D(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/rd_dc_i_mux0002 [9]),
+ .PRE(\BU2/data_count [0]),
+ .Q(rd_data_count_4[9])
+ );
+ FDCP #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/rd_dc_i_8 (
+ .C(rd_clk),
+ .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [2]),
+ .D(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/rd_dc_i_mux0002 [8]),
+ .PRE(\BU2/data_count [0]),
+ .Q(rd_data_count_4[8])
+ );
+ FDCP #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/rd_dc_i_7 (
+ .C(rd_clk),
+ .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [2]),
+ .D(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/rd_dc_i_mux0002 [7]),
+ .PRE(\BU2/data_count [0]),
+ .Q(rd_data_count_4[7])
+ );
+ FDCP #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/rd_dc_i_6 (
+ .C(rd_clk),
+ .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [2]),
+ .D(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/rd_dc_i_mux0002 [6]),
+ .PRE(\BU2/data_count [0]),
+ .Q(rd_data_count_4[6])
+ );
+ FDCP #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/rd_dc_i_5 (
+ .C(rd_clk),
+ .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [2]),
+ .D(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/rd_dc_i_mux0002 [5]),
+ .PRE(\BU2/data_count [0]),
+ .Q(rd_data_count_4[5])
+ );
+ FDCP #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/rd_dc_i_4 (
+ .C(rd_clk),
+ .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [2]),
+ .D(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/rd_dc_i_mux0002 [4]),
+ .PRE(\BU2/data_count [0]),
+ .Q(rd_data_count_4[4])
+ );
+ FDCP #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/rd_dc_i_3 (
+ .C(rd_clk),
+ .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [2]),
+ .D(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/rd_dc_i_mux0002 [3]),
+ .PRE(\BU2/data_count [0]),
+ .Q(rd_data_count_4[3])
+ );
+ FDCP #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/rd_dc_i_2 (
+ .C(rd_clk),
+ .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [2]),
+ .D(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/rd_dc_i_mux0002 [2]),
+ .PRE(\BU2/data_count [0]),
+ .Q(rd_data_count_4[2])
+ );
+ FDCP #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/rd_dc_i_1 (
+ .C(rd_clk),
+ .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [2]),
+ .D(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/rd_dc_i_mux0002 [1]),
+ .PRE(\BU2/data_count [0]),
+ .Q(rd_data_count_4[1])
+ );
+ FDCP #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/rd_dc_i_0 (
+ .C(rd_clk),
+ .CLR(\BU2/U0/grf.rf/rstblk/rd_rst_reg [2]),
+ .D(\BU2/U0/grf.rf/gl0.rd/gr1.grdc2.rdc/rd_dc_i_mux0002 [0]),
+ .PRE(\BU2/data_count [0]),
+ .Q(rd_data_count_4[0])
+ );
+ FDP #(
+ .INIT ( 1'b1 ))
+ \BU2/U0/grf.rf/gl0.rd/gras.rsts/ram_empty_fb_i (
+ .C(rd_clk),
+ .D(\BU2/U0/grf.rf/gl0.rd/gras.rsts/ram_empty_fb_i_or0000 ),
+ .PRE(\BU2/U0/grf.rf/rstblk/rd_rst_reg [2]),
+ .Q(\BU2/U0/grf.rf/gl0.rd/gras.rsts/ram_empty_fb_i_81 )
+ );
+ FDP #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/rstblk/wr_rst_reg_0 (
+ .C(wr_clk),
+ .D(\BU2/data_count [0]),
+ .PRE(\BU2/U0/grf.rf/rstblk/wr_rst_comb ),
+ .Q(\BU2/U0/grf.rf/rstblk/wr_rst_reg [0])
+ );
+ FDP #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/rstblk/wr_rst_reg_1 (
+ .C(wr_clk),
+ .D(\BU2/data_count [0]),
+ .PRE(\BU2/U0/grf.rf/rstblk/wr_rst_comb ),
+ .Q(\BU2/U0/grf.rf/rstblk/wr_rst_reg [1])
+ );
+ FDP #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/rstblk/rd_rst_reg_0 (
+ .C(rd_clk),
+ .D(\BU2/data_count [0]),
+ .PRE(\BU2/U0/grf.rf/rstblk/rd_rst_comb ),
+ .Q(\BU2/U0/grf.rf/rstblk/rd_rst_reg [0])
+ );
+ FDP #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/rstblk/rd_rst_reg_1 (
+ .C(rd_clk),
+ .D(\BU2/data_count [0]),
+ .PRE(\BU2/U0/grf.rf/rstblk/rd_rst_comb ),
+ .Q(\BU2/U0/grf.rf/rstblk/rd_rst_reg [1])
+ );
+ FDP #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/rstblk/rd_rst_reg_2 (
+ .C(rd_clk),
+ .D(\BU2/data_count [0]),
+ .PRE(\BU2/U0/grf.rf/rstblk/rd_rst_comb ),
+ .Q(\BU2/U0/grf.rf/rstblk/rd_rst_reg [2])
+ );
+ FDPE #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/rstblk/rd_rst_asreg (
+ .C(rd_clk),
+ .CE(\BU2/U0/grf.rf/rstblk/rd_rst_asreg_d1_67 ),
+ .D(\BU2/data_count [0]),
+ .PRE(rst),
+ .Q(\BU2/U0/grf.rf/rstblk/rd_rst_asreg_71 )
+ );
+ FD #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/rstblk/wr_rst_asreg_d1 (
+ .C(wr_clk),
+ .D(\BU2/U0/grf.rf/rstblk/wr_rst_asreg_72 ),
+ .Q(\BU2/U0/grf.rf/rstblk/wr_rst_asreg_d1_69 )
+ );
+ FDPE #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/rstblk/wr_rst_asreg (
+ .C(wr_clk),
+ .CE(\BU2/U0/grf.rf/rstblk/wr_rst_asreg_d1_69 ),
+ .D(\BU2/data_count [0]),
+ .PRE(rst),
+ .Q(\BU2/U0/grf.rf/rstblk/wr_rst_asreg_72 )
+ );
+ FD #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/rstblk/rd_rst_asreg_d1 (
+ .C(rd_clk),
+ .D(\BU2/U0/grf.rf/rstblk/rd_rst_asreg_71 ),
+ .Q(\BU2/U0/grf.rf/rstblk/rd_rst_asreg_d1_67 )
+ );
+ FD #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/rstblk/wr_rst_asreg_d2 (
+ .C(wr_clk),
+ .D(\BU2/U0/grf.rf/rstblk/wr_rst_asreg_d1_69 ),
+ .Q(\BU2/U0/grf.rf/rstblk/wr_rst_asreg_d2_70 )
+ );
+ FD #(
+ .INIT ( 1'b0 ))
+ \BU2/U0/grf.rf/rstblk/rd_rst_asreg_d2 (
+ .C(rd_clk),
+ .D(\BU2/U0/grf.rf/rstblk/rd_rst_asreg_d1_67 ),
+ .Q(\BU2/U0/grf.rf/rstblk/rd_rst_asreg_d2_68 )
+ );
+ VCC \BU2/XST_VCC (
+ .P(\BU2/N1 )
+ );
+ GND \BU2/XST_GND (
+ .G(\BU2/data_count [0])
+ );
+
+// synthesis translate_on
+
+endmodule
+
+// synthesis translate_off
+
+`timescale 1 ps / 1 ps
+
+module glbl ();
+
+ parameter ROC_WIDTH = 100000;
+ parameter TOC_WIDTH = 0;
+
+ wire GSR;
+ wire GTS;
+ wire PRLD;
+
+ reg GSR_int;
+ reg GTS_int;
+ reg PRLD_int;
+
+//-------- JTAG Globals --------------
+ wire JTAG_TDO_GLBL;
+ wire JTAG_TCK_GLBL;
+ wire JTAG_TDI_GLBL;
+ wire JTAG_TMS_GLBL;
+ wire JTAG_TRST_GLBL;
+
+ reg JTAG_CAPTURE_GLBL;
+ reg JTAG_RESET_GLBL;
+ reg JTAG_SHIFT_GLBL;
+ reg JTAG_UPDATE_GLBL;
+
+ reg JTAG_SEL1_GLBL = 0;
+ reg JTAG_SEL2_GLBL = 0 ;
+ reg JTAG_SEL3_GLBL = 0;
+ reg JTAG_SEL4_GLBL = 0;
+
+ reg JTAG_USER_TDO1_GLBL = 1'bz;
+ reg JTAG_USER_TDO2_GLBL = 1'bz;
+ reg JTAG_USER_TDO3_GLBL = 1'bz;
+ reg JTAG_USER_TDO4_GLBL = 1'bz;
+
+ assign (weak1, weak0) GSR = GSR_int;
+ assign (weak1, weak0) GTS = GTS_int;
+ assign (weak1, weak0) PRLD = PRLD_int;
+
+ initial begin
+ GSR_int = 1'b1;
+ PRLD_int = 1'b1;
+ #(ROC_WIDTH)
+ GSR_int = 1'b0;
+ PRLD_int = 1'b0;
+ end
+
+ initial begin
+ GTS_int = 1'b1;
+ #(TOC_WIDTH)
+ GTS_int = 1'b0;
+ end
+
+endmodule
+
+// synthesis translate_on
diff --git a/fpga/usrp2/coregen/fifo_xlnx_1Kx18_2clk.veo b/fpga/usrp2/coregen/fifo_xlnx_1Kx18_2clk.veo
new file mode 100644
index 000000000..c98e03c3b
--- /dev/null
+++ b/fpga/usrp2/coregen/fifo_xlnx_1Kx18_2clk.veo
@@ -0,0 +1,47 @@
+/*******************************************************************************
+* This file is owned and controlled by Xilinx and must be used *
+* solely for design, simulation, implementation and creation of *
+* design files limited to Xilinx devices or technologies. Use *
+* with non-Xilinx devices or technologies is expressly prohibited *
+* and immediately terminates your license. *
+* *
+* XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS" *
+* SOLELY FOR USE IN DEVELOPING PROGRAMS AND SOLUTIONS FOR *
+* XILINX DEVICES. BY PROVIDING THIS DESIGN, CODE, OR INFORMATION *
+* AS ONE POSSIBLE IMPLEMENTATION OF THIS FEATURE, APPLICATION *
+* OR STANDARD, XILINX IS MAKING NO REPRESENTATION THAT THIS *
+* IMPLEMENTATION IS FREE FROM ANY CLAIMS OF INFRINGEMENT, *
+* AND YOU ARE RESPONSIBLE FOR OBTAINING ANY RIGHTS YOU MAY REQUIRE *
+* FOR YOUR IMPLEMENTATION. XILINX EXPRESSLY DISCLAIMS ANY *
+* WARRANTY WHATSOEVER WITH RESPECT TO THE ADEQUACY OF THE *
+* IMPLEMENTATION, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OR *
+* REPRESENTATIONS THAT THIS IMPLEMENTATION IS FREE FROM CLAIMS OF *
+* INFRINGEMENT, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS *
+* FOR A PARTICULAR PURPOSE. *
+* *
+* Xilinx products are not intended for use in life support *
+* appliances, devices, or systems. Use in such applications are *
+* expressly prohibited. *
+* *
+* (c) Copyright 1995-2007 Xilinx, Inc. *
+* All rights reserved. *
+*******************************************************************************/
+// The following must be inserted into your Verilog file for this
+// core to be instantiated. Change the instance name and port connections
+// (in parentheses) to your own signal names.
+
+//----------- Begin Cut here for INSTANTIATION Template ---// INST_TAG
+fifo_xlnx_1Kx18_2clk YourInstanceName (
+ .din(din), // Bus [17 : 0]
+ .rd_clk(rd_clk),
+ .rd_en(rd_en),
+ .rst(rst),
+ .wr_clk(wr_clk),
+ .wr_en(wr_en),
+ .dout(dout), // Bus [17 : 0]
+ .empty(empty),
+ .full(full),
+ .rd_data_count(rd_data_count), // Bus [10 : 0]
+ .wr_data_count(wr_data_count)); // Bus [10 : 0]
+
+// INST_TAG_END ------ End INSTANTIATION Template ---------
diff --git a/fpga/usrp2/coregen/fifo_xlnx_1Kx18_2clk.xco b/fpga/usrp2/coregen/fifo_xlnx_1Kx18_2clk.xco
new file mode 100644
index 000000000..082aef22b
--- /dev/null
+++ b/fpga/usrp2/coregen/fifo_xlnx_1Kx18_2clk.xco
@@ -0,0 +1,82 @@
+##############################################################
+#
+# Xilinx Core Generator version K.39
+# Date: Fri Jun 10 23:12:12 2011
+#
+##############################################################
+#
+# This file contains the customisation parameters for a
+# Xilinx CORE Generator IP GUI. It is strongly recommended
+# that you do not manually alter this file as it may cause
+# unexpected and unsupported behavior.
+#
+##############################################################
+#
+# BEGIN Project Options
+SET addpads = false
+SET asysymbol = false
+SET busformat = BusFormatAngleBracketNotRipped
+SET createndf = false
+SET designentry = Verilog
+SET device = xc3s2000
+SET devicefamily = spartan3
+SET flowvendor = Other
+SET formalverification = false
+SET foundationsym = false
+SET implementationfiletype = Ngc
+SET package = fg456
+SET removerpms = false
+SET simulationfiles = Structural
+SET speedgrade = -5
+SET verilogsim = true
+SET vhdlsim = false
+# END Project Options
+# BEGIN Select
+SELECT Fifo_Generator family Xilinx,_Inc. 4.3
+# END Select
+# BEGIN Parameters
+CSET almost_empty_flag=false
+CSET almost_full_flag=false
+CSET component_name=fifo_xlnx_1Kx18_2clk
+CSET data_count=false
+CSET data_count_width=11
+CSET disable_timing_violations=false
+CSET dout_reset_value=0
+CSET empty_threshold_assert_value=4
+CSET empty_threshold_negate_value=5
+CSET enable_ecc=false
+CSET enable_int_clk=false
+CSET fifo_implementation=Independent_Clocks_Block_RAM
+CSET full_flags_reset_value=1
+CSET full_threshold_assert_value=1023
+CSET full_threshold_negate_value=1022
+CSET input_data_width=18
+CSET input_depth=1024
+CSET output_data_width=18
+CSET output_depth=1024
+CSET overflow_flag=false
+CSET overflow_sense=Active_High
+CSET performance_options=First_Word_Fall_Through
+CSET programmable_empty_type=No_Programmable_Empty_Threshold
+CSET programmable_full_type=No_Programmable_Full_Threshold
+CSET read_clock_frequency=1
+CSET read_data_count=true
+CSET read_data_count_width=11
+CSET reset_pin=true
+CSET reset_type=Asynchronous_Reset
+CSET underflow_flag=false
+CSET underflow_sense=Active_High
+CSET use_dout_reset=true
+CSET use_embedded_registers=false
+CSET use_extra_logic=true
+CSET valid_flag=false
+CSET valid_sense=Active_High
+CSET write_acknowledge_flag=false
+CSET write_acknowledge_sense=Active_High
+CSET write_clock_frequency=1
+CSET write_data_count=true
+CSET write_data_count_width=11
+# END Parameters
+GENERATE
+# CRC: c3fb8408
+
diff --git a/fpga/usrp2/coregen/fifo_xlnx_1Kx18_2clk_fifo_generator_v4_3_xst_1.lso b/fpga/usrp2/coregen/fifo_xlnx_1Kx18_2clk_fifo_generator_v4_3_xst_1.lso
new file mode 100644
index 000000000..f1a6f7899
--- /dev/null
+++ b/fpga/usrp2/coregen/fifo_xlnx_1Kx18_2clk_fifo_generator_v4_3_xst_1.lso
@@ -0,0 +1,3 @@
+blkmemdp_v6_2
+blk_mem_gen_v2_6
+fifo_generator_v4_3
diff --git a/fpga/usrp2/coregen/fifo_xlnx_1Kx18_2clk_fifo_generator_v4_3_xst_1.ngc_xst.xrpt b/fpga/usrp2/coregen/fifo_xlnx_1Kx18_2clk_fifo_generator_v4_3_xst_1.ngc_xst.xrpt
new file mode 100644
index 000000000..be22cb8dc
--- /dev/null
+++ b/fpga/usrp2/coregen/fifo_xlnx_1Kx18_2clk_fifo_generator_v4_3_xst_1.ngc_xst.xrpt
@@ -0,0 +1,106 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
+<document OS="lin64" product="ISE" version="10.1.03">
+
+ <!--The data in this file is primarily intended for consumption by Xilinx tools.
+ The structure and the elements are likely to change over the next few releases.
+ This means code written to parse this file will need to be revisited each subsequent release.-->
+
+ <application stringID="Xst" timeStamp="Fri Jun 10 16:11:52 2011">
+ <section stringID="XST_HDL_SYNTHESIS_REPORT">
+ <item dataType="int" stringID="XST_ADDERSSUBTRACTORS" value="4"></item>
+ <item dataType="int" stringID="XST_COUNTERS" value="2">
+ <item dataType="int" stringID="XST_10BIT_UP_COUNTER" value="2"/>
+ </item>
+ <item dataType="int" stringID="XST_REGISTERS" value="31">
+ <item dataType="int" stringID="XST_1BIT_REGISTER" value="15"/>
+ <item dataType="int" stringID="XST_10BIT_REGISTER" value="11"/>
+ <item dataType="int" stringID="XST_11BIT_REGISTER" value="2"/>
+ <item dataType="int" stringID="XST_2BIT_REGISTER" value="1"/>
+ <item dataType="int" stringID="XST_3BIT_REGISTER" value="1"/>
+ </item>
+ <item dataType="int" stringID="XST_XORS" value="76">
+ <item dataType="int" stringID="XST_1BIT_XOR2" value="76"/>
+ </item>
+ </section>
+ <section stringID="XST_ADVANCED_HDL_SYNTHESIS_REPORT">
+ <item dataType="int" stringID="XST_FSMS" value="1"/>
+ <item dataType="int" stringID="XST_ADDERSSUBTRACTORS" value="4"></item>
+ <item dataType="int" stringID="XST_COUNTERS" value="2">
+ <item dataType="int" stringID="XST_10BIT_UP_COUNTER" value="2"/>
+ </item>
+ <item dataType="int" stringID="XST_REGISTERS" value="159">
+ <item dataType="int" stringID="XST_FLIPFLOPS" value="159"/>
+ </item>
+ <item dataType="int" stringID="XST_XORS" value="76">
+ <item dataType="int" stringID="XST_1BIT_XOR2" value="76"/>
+ </item>
+ </section>
+ <section stringID="XST_FINAL_REGISTER_REPORT">
+ <item dataType="int" stringID="XST_REGISTERS" value="189">
+ <item dataType="int" stringID="XST_FLIPFLOPS" value="189"/>
+ </item>
+ </section>
+ <section stringID="XST_PARTITION_REPORT">
+ <section stringID="XST_PARTITION_IMPLEMENTATION_STATUS">
+ <section stringID="XST_NO_PARTITIONS_WERE_FOUND_IN_THIS_DESIGN"/>
+ </section>
+ </section>
+ <section stringID="XST_FINAL_REPORT">
+ <section stringID="XST_FINAL_RESULTS">
+ <item stringID="XST_TOP_LEVEL_OUTPUT_FILE_NAME" value="/tmp/_cg/fifo_xlnx_1Kx18_2clk_fifo_generator_v4_3_xst_1.ngc"/>
+ <item stringID="XST_OUTPUT_FORMAT" value="NGC"/>
+ <item stringID="XST_OPTIMIZATION_GOAL" value="SPEED"/>
+ <item stringID="XST_KEEP_HIERARCHY" value="no"/>
+ </section>
+ <section stringID="XST_DESIGN_STATISTICS">
+ <item stringID="XST_IOS" value="153"/>
+ </section>
+ <section stringID="XST_CELL_USAGE">
+ <item dataType="int" stringID="XST_BELS" value="248">
+ <item dataType="int" stringID="XST_GND" value="1"/>
+ <item dataType="int" stringID="XST_INV" value="1"/>
+ <item dataType="int" stringID="XST_LUT1" value="20"/>
+ <item dataType="int" stringID="XST_LUT2" value="52"/>
+ <item dataType="int" stringID="XST_LUT2D" value="1"/>
+ <item dataType="int" stringID="XST_LUT3" value="14"/>
+ <item dataType="int" stringID="XST_LUT3D" value="3"/>
+ <item dataType="int" stringID="XST_LUT3L" value="1"/>
+ <item dataType="int" stringID="XST_LUT4" value="54"/>
+ <item dataType="int" stringID="XST_LUT4D" value="2"/>
+ <item dataType="int" stringID="XST_LUT4L" value="2"/>
+ <item dataType="int" stringID="XST_MUXCY" value="56"/>
+ <item dataType="int" stringID="XST_VCC" value="1"/>
+ <item dataType="int" stringID="XST_XORCY" value="40"/>
+ </item>
+ <item dataType="int" stringID="XST_FLIPFLOPSLATCHES" value="189">
+ <item dataType="int" stringID="XST_FD" value="4"/>
+ <item dataType="int" stringID="XST_FDC" value="94"/>
+ <item dataType="int" stringID="XST_FDCE" value="65"/>
+ <item dataType="int" stringID="XST_FDP" value="10"/>
+ <item dataType="int" stringID="XST_FDPE" value="5"/>
+ </item>
+ <item dataType="int" stringID="XST_RAMS" value="1">
+ <item dataType="int" stringID="XST_RAMB16S18S18" value="1"/>
+ </item>
+ </section>
+ </section>
+ <section stringID="XST_DEVICE_UTILIZATION_SUMMARY">
+ <item stringID="XST_SELECTED_DEVICE" value="3s2000fg456-5"/>
+ <item AVAILABLE="20480" dataType="int" stringID="XST_NUMBER_OF_SLICES" value="139"/>
+ <item AVAILABLE="40960" dataType="int" stringID="XST_NUMBER_OF_SLICE_FLIP_FLOPS" value="189"/>
+ <item AVAILABLE="40960" dataType="int" stringID="XST_NUMBER_OF_4_INPUT_LUTS" value="150"/>
+ <item dataType="int" stringID="XST_NUMBER_OF_IOS" value="153"/>
+ <item AVAILABLE="333" dataType="int" stringID="XST_NUMBER_OF_BONDED_IOBS" value="0"/>
+ <item AVAILABLE="40" dataType="int" stringID="XST_NUMBER_OF_BRAMS" value="1"/>
+ </section>
+ <section stringID="XST_PARTITION_RESOURCE_SUMMARY">
+ <section stringID="XST_NO_PARTITIONS_WERE_FOUND_IN_THIS_DESIGN"/>
+ </section>
+ <section stringID="XST_ERRORS_STATISTICS">
+ <item dataType="int" filtered="0" stringID="XST_NUMBER_OF_ERRORS" value="0"/>
+ <item dataType="int" filtered="0" stringID="XST_NUMBER_OF_WARNINGS" value="136"/>
+ <item dataType="int" filtered="0" stringID="XST_NUMBER_OF_INFOS" value="17"/>
+ </section>
+ </application>
+
+</document>
diff --git a/fpga/usrp2/coregen/fifo_xlnx_1Kx18_2clk_flist.txt b/fpga/usrp2/coregen/fifo_xlnx_1Kx18_2clk_flist.txt
new file mode 100644
index 000000000..3bd308751
--- /dev/null
+++ b/fpga/usrp2/coregen/fifo_xlnx_1Kx18_2clk_flist.txt
@@ -0,0 +1,8 @@
+# Output products list for <fifo_xlnx_1Kx18_2clk>
+fifo_xlnx_1Kx18_2clk.ngc
+fifo_xlnx_1Kx18_2clk.v
+fifo_xlnx_1Kx18_2clk.veo
+fifo_xlnx_1Kx18_2clk.xco
+fifo_xlnx_1Kx18_2clk_fifo_generator_v4_3_xst_1.ngc_xst.xrpt
+fifo_xlnx_1Kx18_2clk_flist.txt
+fifo_xlnx_1Kx18_2clk_xmdf.tcl
diff --git a/fpga/usrp2/coregen/fifo_xlnx_1Kx18_2clk_readme.txt b/fpga/usrp2/coregen/fifo_xlnx_1Kx18_2clk_readme.txt
new file mode 100644
index 000000000..72f83d6fb
--- /dev/null
+++ b/fpga/usrp2/coregen/fifo_xlnx_1Kx18_2clk_readme.txt
@@ -0,0 +1,38 @@
+The following files were generated for 'fifo_xlnx_1Kx18_2clk' in directory
+/home/matt/sourcerepo/fpga/usrp2/coregen/:
+
+fifo_xlnx_1Kx18_2clk.ngc:
+ Binary Xilinx implementation netlist file containing the information
+ required to implement the module in a Xilinx (R) FPGA.
+
+fifo_xlnx_1Kx18_2clk.v:
+ Unisim Verilog file containing the information required to simulate
+ the module.
+
+fifo_xlnx_1Kx18_2clk.veo:
+ VEO template file containing code that can be used as a model for
+ instantiating a CORE Generator module in a Verilog design.
+
+fifo_xlnx_1Kx18_2clk.xco:
+ CORE Generator input file containing the parameters used to
+ regenerate a core.
+
+fifo_xlnx_1Kx18_2clk_fifo_generator_v4_3_xst_1.ngc_xst.xrpt:
+ Please see the core data sheet.
+
+fifo_xlnx_1Kx18_2clk_flist.txt:
+ Text file listing all of the output files produced when a customized
+ core was generated in the CORE Generator.
+
+fifo_xlnx_1Kx18_2clk_readme.txt:
+ Text file indicating the files generated and how they are used.
+
+fifo_xlnx_1Kx18_2clk_xmdf.tcl:
+ ISE Project Navigator interface file. ISE uses this file to determine
+ how the files output by CORE Generator for the core can be integrated
+ into your ISE project.
+
+
+Please see the Xilinx CORE Generator online help for further details on
+generated files and how to use them.
+
diff --git a/fpga/usrp2/coregen/fifo_xlnx_1Kx18_2clk_xmdf.tcl b/fpga/usrp2/coregen/fifo_xlnx_1Kx18_2clk_xmdf.tcl
new file mode 100644
index 000000000..244d03d85
--- /dev/null
+++ b/fpga/usrp2/coregen/fifo_xlnx_1Kx18_2clk_xmdf.tcl
@@ -0,0 +1,68 @@
+# The package naming convention is <core_name>_xmdf
+package provide fifo_xlnx_1Kx18_2clk_xmdf 1.0
+
+# This includes some utilities that support common XMDF operations
+package require utilities_xmdf
+
+# Define a namespace for this package. The name of the name space
+# is <core_name>_xmdf
+namespace eval ::fifo_xlnx_1Kx18_2clk_xmdf {
+# Use this to define any statics
+}
+
+# Function called by client to rebuild the params and port arrays
+# Optional when the use context does not require the param or ports
+# arrays to be available.
+proc ::fifo_xlnx_1Kx18_2clk_xmdf::xmdfInit { instance } {
+# Variable containg name of library into which module is compiled
+# Recommendation: <module_name>
+# Required
+utilities_xmdf::xmdfSetData $instance Module Attributes Name fifo_xlnx_1Kx18_2clk
+}
+# ::fifo_xlnx_1Kx18_2clk_xmdf::xmdfInit
+
+# Function called by client to fill in all the xmdf* data variables
+# based on the current settings of the parameters
+proc ::fifo_xlnx_1Kx18_2clk_xmdf::xmdfApplyParams { instance } {
+
+set fcount 0
+# Array containing libraries that are assumed to exist
+# Examples include unisim and xilinxcorelib
+# Optional
+# In this example, we assume that the unisim library will
+# be magically
+# available to the simulation and synthesis tool
+utilities_xmdf::xmdfSetData $instance FileSet $fcount type logical_library
+utilities_xmdf::xmdfSetData $instance FileSet $fcount logical_library unisim
+incr fcount
+
+utilities_xmdf::xmdfSetData $instance FileSet $fcount relative_path fifo_xlnx_1Kx18_2clk.ngc
+utilities_xmdf::xmdfSetData $instance FileSet $fcount type ngc
+incr fcount
+
+utilities_xmdf::xmdfSetData $instance FileSet $fcount relative_path fifo_xlnx_1Kx18_2clk.v
+utilities_xmdf::xmdfSetData $instance FileSet $fcount type verilog
+incr fcount
+
+utilities_xmdf::xmdfSetData $instance FileSet $fcount relative_path fifo_xlnx_1Kx18_2clk.veo
+utilities_xmdf::xmdfSetData $instance FileSet $fcount type verilog_template
+incr fcount
+
+utilities_xmdf::xmdfSetData $instance FileSet $fcount relative_path fifo_xlnx_1Kx18_2clk.xco
+utilities_xmdf::xmdfSetData $instance FileSet $fcount type coregen_ip
+incr fcount
+
+utilities_xmdf::xmdfSetData $instance FileSet $fcount relative_path fifo_xlnx_1Kx18_2clk_fifo_generator_v4_3_xst_1.ngc_xst.xrpt
+utilities_xmdf::xmdfSetData $instance FileSet $fcount type AnyView
+incr fcount
+
+utilities_xmdf::xmdfSetData $instance FileSet $fcount relative_path fifo_xlnx_1Kx18_2clk_xmdf.tcl
+utilities_xmdf::xmdfSetData $instance FileSet $fcount type AnyView
+incr fcount
+
+utilities_xmdf::xmdfSetData $instance FileSet $fcount associated_module fifo_xlnx_1Kx18_2clk
+incr fcount
+
+}
+
+# ::gen_comp_name_xmdf::xmdfApplyParams
diff --git a/fpga/usrp2/fifo/fifo_2clock.v b/fpga/usrp2/fifo/fifo_2clock.v
index 756ad508f..c6aaf34dc 100644
--- a/fpga/usrp2/fifo/fifo_2clock.v
+++ b/fpga/usrp2/fifo/fifo_2clock.v
@@ -65,6 +65,11 @@ module fifo_2clock
(.rst(arst),
.wr_clk(wclk),.din({1'b0,datain}),.full(full),.wr_en(write),.wr_data_count(level_wclk),
.rd_clk(rclk),.dout({dummy,dataout}),.empty(empty),.rd_en(read),.rd_data_count(level_rclk) );
+ else if ((WIDTH==18) & (SIZE==10))
+ fifo_xlnx_1Kx18_2clk fifo_xlnx_1Kx18_2clk
+ (.rst(arst),
+ .wr_clk(wclk),.din(datain),.full(full),.wr_en(write),.wr_data_count(level_wclk),
+ .rd_clk(rclk),.dout(dataout),.empty(empty),.rd_en(read),.rd_data_count(level_rclk) );
endgenerate
assign occupied = {{(16-SIZE-1){1'b0}},level_rclk};
diff --git a/fpga/usrp2/gpmc/Makefile.srcs b/fpga/usrp2/gpmc/Makefile.srcs
index bff6ae3e0..bf0c0ecfd 100644
--- a/fpga/usrp2/gpmc/Makefile.srcs
+++ b/fpga/usrp2/gpmc/Makefile.srcs
@@ -17,4 +17,6 @@ gpmc_to_fifo_async.v \
gpmc_to_fifo_sync.v \
gpmc_wb.v \
ram_to_fifo.v \
+new_write.v \
+new_read.v \
))
diff --git a/fpga/usrp2/gpmc/fifo_watcher.v b/fpga/usrp2/gpmc/fifo_watcher.v
index b139f5143..3971e3c54 100644
--- a/fpga/usrp2/gpmc/fifo_watcher.v
+++ b/fpga/usrp2/gpmc/fifo_watcher.v
@@ -30,10 +30,11 @@ module fifo_watcher
reg [15:0] counter;
wire [4:0] pkt_count;
assign debug = pkt_count;
+ wire space;
fifo_short #(.WIDTH(16)) frame_lengths
(.clk(clk), .reset(reset), .clear(clear),
- .datain(counter), .src_rdy_i(write), .dst_rdy_o(),
+ .datain(counter), .src_rdy_i(write), .dst_rdy_o(space),
.dataout(length), .src_rdy_o(have_packet_int), .dst_rdy_i(read),
.occupied(pkt_count), .space());
@@ -53,7 +54,9 @@ module fifo_watcher
bus_error <= 1;
else if(read & ~have_packet_int)
bus_error <= 1;
-
+ else if(write & ~space)
+ bus_error <= 1;
+
reg in_packet;
always @(posedge clk)
if(reset | clear)
diff --git a/fpga/usrp2/gpmc/gpmc_async.v b/fpga/usrp2/gpmc/gpmc_async.v
index c0bec683a..9972e81b0 100644
--- a/fpga/usrp2/gpmc/gpmc_async.v
+++ b/fpga/usrp2/gpmc/gpmc_async.v
@@ -22,7 +22,7 @@ module gpmc_async
parameter RXFIFOSIZE = 11,
parameter BUSDEBUG = 1)
(// GPMC signals
- input arst,
+ input arst, input bus_clk,
input EM_CLK, inout [15:0] EM_D, input [10:1] EM_A, input [1:0] EM_NBE,
input EM_WAIT0, input EM_NCS4, input EM_NCS6, input EM_NWE, input EM_NOE,
@@ -67,27 +67,21 @@ module gpmc_async
// ////////////////////////////////////////////
// TX Data Path
- wire [17:0] tx18_data, tx18b_data;
- wire tx18_src_rdy, tx18_dst_rdy, tx18b_src_rdy, tx18b_dst_rdy;
+ wire [17:0] tx18_data;
+ wire tx18_src_rdy, tx18_dst_rdy;
wire [15:0] tx_fifo_space;
wire [35:0] tx36_data, tx_data;
wire tx36_src_rdy, tx36_dst_rdy, tx_src_rdy, tx_dst_rdy;
- gpmc_to_fifo_async gpmc_to_fifo_async
+ new_write new_write
(.EM_D(EM_D), .EM_NBE(EM_NBE), .EM_NCS(EM_NCS4), .EM_NWE(EM_NWE),
- .fifo_clk(fifo_clk), .fifo_rst(fifo_rst), .clear(clear_tx),
+ .bus_clk(bus_clk), .fifo_clk(fifo_clk), .fifo_rst(fifo_rst), .clear(clear_tx),
.data_o(tx18_data), .src_rdy_o(tx18_src_rdy), .dst_rdy_i(tx18_dst_rdy),
- .frame_len(tx_frame_len), .fifo_space(tx_fifo_space), .fifo_ready(tx_have_space),
- .bus_error(bus_error_tx) );
+ .frame_len(tx_frame_len), .fifo_ready(tx_have_space), .bus_error(bus_error_tx) );
- fifo_cascade #(.WIDTH(18), .SIZE(10)) tx_fifo
- (.clk(fifo_clk), .reset(fifo_rst), .clear(clear_tx),
- .datain(tx18_data), .src_rdy_i(tx18_src_rdy), .dst_rdy_o(tx18_dst_rdy), .space(tx_fifo_space),
- .dataout(tx18b_data), .src_rdy_o(tx18b_src_rdy), .dst_rdy_i(tx18b_dst_rdy), .occupied());
-
fifo19_to_fifo36 #(.LE(1)) f19_to_f36 // Little endian because ARM is LE
(.clk(fifo_clk), .reset(fifo_rst), .clear(clear_tx),
- .f19_datain({1'b0,tx18b_data}), .f19_src_rdy_i(tx18b_src_rdy), .f19_dst_rdy_o(tx18b_dst_rdy),
+ .f19_datain({1'b0,tx18_data}), .f19_src_rdy_i(tx18_src_rdy), .f19_dst_rdy_o(tx18_dst_rdy),
.f36_dataout(tx36_data), .f36_src_rdy_o(tx36_src_rdy), .f36_dst_rdy_i(tx36_dst_rdy));
fifo_cascade #(.WIDTH(36), .SIZE(TXFIFOSIZE)) tx_fifo36
@@ -110,31 +104,20 @@ module gpmc_async
.datain(rx_data), .src_rdy_i(rx_src_rdy), .dst_rdy_o(rx_dst_rdy),
.dataout(rx36_data), .src_rdy_o(rx36_src_rdy), .dst_rdy_i(rx36_dst_rdy));
+ wire [31:0] pkt_count;
+ wire throttle = pkt_count == 16;
+
fifo36_to_fifo19 #(.LE(1)) f36_to_f19 // Little endian because ARM is LE
(.clk(fifo_clk), .reset(fifo_rst), .clear(clear_rx),
.f36_datain(rx36_data), .f36_src_rdy_i(rx36_src_rdy), .f36_dst_rdy_o(rx36_dst_rdy),
.f19_dataout({dummy,rx18_data}), .f19_src_rdy_o(rx18_src_rdy), .f19_dst_rdy_i(rx18_dst_rdy) );
- fifo_cascade #(.WIDTH(18), .SIZE(12)) rx_fifo
- (.clk(fifo_clk), .reset(fifo_rst), .clear(clear_rx),
- .datain(rx18_data), .src_rdy_i(rx18_src_rdy), .dst_rdy_o(rx18_dst_rdy), .space(rx_fifo_space),
- .dataout(rx18b_data), .src_rdy_o(rx18b_src_rdy), .dst_rdy_i(rx18b_dst_rdy), .occupied());
-
- fifo_to_gpmc_async fifo_to_gpmc_async
+ new_read new_read
(.clk(fifo_clk), .reset(fifo_rst), .clear(clear_rx),
- .data_i(rx18b_data), .src_rdy_i(rx18b_src_rdy), .dst_rdy_o(rx18b_dst_rdy),
+ .data_i(rx18_data), .src_rdy_i(rx18_src_rdy), .dst_rdy_o(rx18_dst_rdy),
.EM_D(EM_D_fifo), .EM_NCS(EM_NCS4), .EM_NOE(EM_NOE),
- .frame_len(rx_frame_len) );
-
- wire [31:0] pkt_count;
+ .have_packet(rx_have_data), .frame_len(rx_frame_len), .bus_error(bus_error_rx) );
- fifo_watcher fifo_watcher
- (.clk(fifo_clk), .reset(fifo_rst), .clear(clear_rx),
- .src_rdy1(rx18_src_rdy), .dst_rdy1(rx18_dst_rdy), .sof1(rx18_data[16]), .eof1(rx18_data[17]),
- .src_rdy2(rx18b_src_rdy), .dst_rdy2(rx18b_dst_rdy), .sof2(rx18b_data[16]), .eof2(rx18b_data[17]),
- .have_packet(rx_have_data), .length(rx_frame_len), .bus_error(bus_error_rx),
- .debug(pkt_count));
-
// ////////////////////////////////////////////
// Control path on CS6
@@ -230,16 +213,13 @@ module gpmc_async
// FIXME -- make sure packet completes before we shutoff
// FIXME -- handle overrun and underrun
-wire [0:17] dummy18;
-
-assign debug = {8'd0,
- test_rate,
- pkt_src_enable, pkt_sink_enable, timedrx_src_rdy_int, timedrx_dst_rdy_int,
- timedrx_src_rdy, timedrx_dst_rdy,
- testrx_src_rdy, testrx_dst_rdy,
- rx_src_rdy, rx_dst_rdy,
- rx36_src_rdy, rx36_dst_rdy,
- rx18_src_rdy, rx18_dst_rdy,
- rx18b_src_rdy, rx18b_dst_rdy};
+ wire [0:17] dummy18;
+
+ assign debug = {rx_overrun, tx_underrun, bus_error_tx, bus_error_rx, tx_have_space, rx_have_data, EM_NCS4, EM_NCS6,
+ 6'd0, EM_NOE, EM_NWE,
+ pkt_src_enable, pkt_sink_enable, timedrx_src_rdy_int, timedrx_dst_rdy_int,
+ timedrx_src_rdy, timedrx_dst_rdy,
+ testrx_src_rdy, testrx_dst_rdy,
+ rx_src_rdy, rx_dst_rdy, rx36_src_rdy, rx36_dst_rdy, rx18_src_rdy, rx18_dst_rdy, rx18b_src_rdy, rx18b_dst_rdy};
endmodule // gpmc_async
diff --git a/fpga/usrp2/gpmc/new_read.v b/fpga/usrp2/gpmc/new_read.v
new file mode 100644
index 000000000..ae3db23cf
--- /dev/null
+++ b/fpga/usrp2/gpmc/new_read.v
@@ -0,0 +1,62 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// 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/>.
+//
+
+
+module new_read
+ (input clk, input reset, input clear,
+ input [17:0] data_i, input src_rdy_i, output dst_rdy_o,
+ output reg [15:0] EM_D, input EM_NCS, input EM_NOE,
+ output have_packet, output [15:0] frame_len, output bus_error);
+
+ wire [17:0] data_int;
+ wire src_rdy_int, dst_rdy_int;
+
+ fifo_cascade #(.WIDTH(18), .SIZE(12)) rx_fifo
+ (.clk(clk), .reset(reset), .clear(clear),
+ .datain(data_i), .src_rdy_i(src_rdy_i), .dst_rdy_o(dst_rdy_o), .space(),
+ .dataout(data_int), .src_rdy_o(src_rdy_int), .dst_rdy_i(dst_rdy_int), .occupied());
+
+ fifo_watcher fifo_watcher
+ (.clk(clk), .reset(reset), .clear(clear),
+ .src_rdy1(src_rdy_i), .dst_rdy1(dst_rdy_o), .sof1(data_i[16]), .eof1(data_i[17]),
+ .src_rdy2(src_rdy_int), .dst_rdy2(dst_rdy_int), .sof2(data_int[16]), .eof2(data_int[17]),
+ .have_packet(have_packet), .length(frame_len), .bus_error(bus_error),
+ .debug());
+
+ // Synchronize the async control signals
+ reg [1:0] cs_del, oe_del;
+ reg [15:0] counter;
+
+ always @(posedge clk)
+ if(reset)
+ begin
+ cs_del <= 2'b11;
+ oe_del <= 2'b11;
+ end
+ else
+ begin
+ cs_del <= { cs_del[0], EM_NCS };
+ oe_del <= { oe_del[0], EM_NOE };
+ end
+
+ assign dst_rdy_int = ( ~cs_del[1] & ~oe_del[1] & oe_del[0]); // change output on trailing edge
+
+ //always @(posedge clk) // 3 cycle latency ( OE -> OE_del -> FIFO -> output REG )
+ always @* // 2 cycle latency ( OE -> OE_del -> FIFO )
+ EM_D <= data_int[15:0];
+
+endmodule // new_read
diff --git a/fpga/usrp2/gpmc/new_write.v b/fpga/usrp2/gpmc/new_write.v
new file mode 100644
index 000000000..df0ce19db
--- /dev/null
+++ b/fpga/usrp2/gpmc/new_write.v
@@ -0,0 +1,82 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// 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/>.
+//
+
+
+module new_write
+ (input [15:0] EM_D, input [1:0] EM_NBE, input EM_NCS, input EM_NWE,
+
+ input bus_clk,
+ input fifo_clk, input fifo_rst, input clear,
+ output [17:0] data_o, output src_rdy_o, input dst_rdy_i,
+
+ input [15:0] frame_len, output reg fifo_ready,
+ output reg bus_error );
+
+ wire [15:0] fifo_space;
+ reg [15:0] counter;
+
+ // Synchronize the async control signals
+ reg [1:0] cs_del, we_del;
+ reg [15:0] data_del[0:1];
+
+ always @(posedge bus_clk)
+ if(fifo_rst)
+ begin
+ cs_del <= 2'b11;
+ we_del <= 2'b11;
+ end
+ else
+ begin
+ cs_del <= { cs_del[0], EM_NCS };
+ we_del <= { we_del[0], EM_NWE };
+ data_del[1] <= data_del[0];
+ data_del[0] <= EM_D;
+ end
+
+ wire first_write = (counter == 0);
+ wire last_write = ((counter+1) == frame_len);
+
+ wire [17:0] data_int = {last_write,first_write,data_del[1]};
+ wire src_rdy_int = (~cs_del[1] & ~we_del[1] & we_del[0]); // rising edge
+ wire dst_rdy_int;
+
+ always @(posedge bus_clk)
+ if(fifo_rst | clear)
+ counter <= 0;
+ else if(src_rdy_int)
+ if(last_write)
+ counter <= 0;
+ else
+ counter <= counter + 1;
+
+ always @(posedge bus_clk)
+ if(fifo_rst | clear)
+ fifo_ready <= 0;
+ else
+ fifo_ready <= /* first_write & */ (fifo_space > 16'd1023);
+
+ always @(posedge bus_clk)
+ if(fifo_rst | clear)
+ bus_error <= 0;
+ else if(src_rdy_int & ~dst_rdy_int)
+ bus_error <= 1;
+
+ fifo_2clock_cascade #(.WIDTH(18), .SIZE(10)) tx_fifo
+ (.wclk(bus_clk), .datain(data_int), .src_rdy_i(src_rdy_int), .dst_rdy_o(dst_rdy_int), .space(fifo_space),
+ .rclk(fifo_clk), .dataout(data_o), .src_rdy_o(src_rdy_o), .dst_rdy_i(dst_rdy_i), .occupied(), .arst(fifo_rst));
+
+endmodule // new_write
diff --git a/fpga/usrp2/sdr_lib/Makefile.srcs b/fpga/usrp2/sdr_lib/Makefile.srcs
index 90eede20f..defbced17 100644
--- a/fpga/usrp2/sdr_lib/Makefile.srcs
+++ b/fpga/usrp2/sdr_lib/Makefile.srcs
@@ -8,6 +8,8 @@
SDR_LIB_SRCS = $(abspath $(addprefix $(BASE_DIR)/../sdr_lib/, \
acc.v \
add2.v \
+add2_and_clip.v \
+add2_and_clip_reg.v \
add2_and_round.v \
add2_and_round_reg.v \
add2_reg.v \
@@ -22,16 +24,16 @@ cordic.v \
cordic_z24.v \
cordic_stage.v \
dsp_core_rx.v \
-dsp_core_rx_old.v \
dsp_core_tx.v \
hb_dec.v \
hb_interp.v \
round.v \
round_reg.v \
-rx_control.v \
+round_sd.v \
rx_dcoffset.v \
+rx_frontend.v \
sign_extend.v \
small_hb_dec.v \
small_hb_int.v \
-tx_control.v \
+tx_frontend.v \
))
diff --git a/fpga/usrp2/sdr_lib/add2_and_clip.v b/fpga/usrp2/sdr_lib/add2_and_clip.v
new file mode 100644
index 000000000..663f5d004
--- /dev/null
+++ b/fpga/usrp2/sdr_lib/add2_and_clip.v
@@ -0,0 +1,12 @@
+
+module add2_and_clip
+ #(parameter WIDTH=16)
+ (input [WIDTH-1:0] in1,
+ input [WIDTH-1:0] in2,
+ output [WIDTH-1:0] sum);
+
+ wire [WIDTH:0] sum_int = {in1[WIDTH-1],in1} + {in2[WIDTH-1],in2};
+ clip #(.bits_in(WIDTH+1),.bits_out(WIDTH)) clip
+ (.in(sum_int),.out(sum));
+
+endmodule // add2_and_clip
diff --git a/fpga/usrp2/sdr_lib/add2_and_clip_reg.v b/fpga/usrp2/sdr_lib/add2_and_clip_reg.v
new file mode 100644
index 000000000..8073b3b54
--- /dev/null
+++ b/fpga/usrp2/sdr_lib/add2_and_clip_reg.v
@@ -0,0 +1,25 @@
+
+module add2_and_clip_reg
+ #(parameter WIDTH=16)
+ (input clk,
+ input rst,
+ input [WIDTH-1:0] in1,
+ input [WIDTH-1:0] in2,
+ input strobe_in,
+ output reg [WIDTH-1:0] sum,
+ output reg strobe_out);
+
+ wire [WIDTH-1:0] sum_int;
+
+ add2_and_clip #(.WIDTH(WIDTH)) add2_and_clip (.in1(in1),.in2(in2),.sum(sum_int));
+
+ always @(posedge clk)
+ if(rst)
+ sum <= 0;
+ else if(strobe_in)
+ sum <= sum_int;
+
+ always @(posedge clk)
+ strobe_out <= strobe_in;
+
+endmodule // add2_and_clip_reg
diff --git a/fpga/usrp2/sdr_lib/dsp_core_rx.v b/fpga/usrp2/sdr_lib/dsp_core_rx.v
index 0e69e53f7..639744de7 100644
--- a/fpga/usrp2/sdr_lib/dsp_core_rx.v
+++ b/fpga/usrp2/sdr_lib/dsp_core_rx.v
@@ -21,8 +21,8 @@ module dsp_core_rx
(input clk, input rst,
input set_stb, input [7:0] set_addr, input [31:0] set_data,
- input [13:0] adc_a, input adc_ovf_a,
- input [13:0] adc_b, input adc_ovf_b,
+ input [23:0] adc_i, input adc_ovf_i,
+ input [23:0] adc_q, input adc_ovf_q,
output [31:0] sample,
input run,
@@ -30,70 +30,56 @@ module dsp_core_rx
output [31:0] debug
);
- wire [15:0] scale_i, scale_q;
- wire [13:0] adc_a_ofs, adc_b_ofs;
- reg [13:0] adc_i, adc_q;
wire [31:0] phase_inc;
reg [31:0] phase;
- wire [35:0] prod_i, prod_q;
- wire [23:0] i_cordic, q_cordic;
+ wire [24:0] i_cordic, q_cordic;
+ wire [23:0] i_cordic_clip, q_cordic_clip;
wire [23:0] i_cic, q_cic;
- wire [17:0] i_cic_scaled, q_cic_scaled;
- wire [17:0] i_hb1, q_hb1;
- wire [17:0] i_hb2, q_hb2;
- wire [15:0] i_out, q_out;
-
+ wire [23:0] i_hb1, q_hb1;
+ wire [23:0] i_hb2, q_hb2;
+
wire strobe_cic, strobe_hb1, strobe_hb2;
wire enable_hb1, enable_hb2;
wire [7:0] cic_decim_rate;
+ reg [23:0] adc_i_mux, adc_q_mux;
+ wire realmode;
+ wire swap_iq;
+
setting_reg #(.my_addr(BASE+0)) sr_0
(.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr),
.in(set_data),.out(phase_inc),.changed());
+ /*
setting_reg #(.my_addr(BASE+1)) sr_1
(.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), .width(10)) sr_2
(.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr),
.in(set_data),.out({enable_hb1, enable_hb2, cic_decim_rate}),.changed());
- rx_dcoffset #(.WIDTH(14),.ADDR(BASE+3)) rx_dcoffset_a
- (.clk(clk),.rst(rst),.set_stb(set_stb),.set_addr(set_addr),.set_data(set_data),
- .adc_in(adc_a),.adc_out(adc_a_ofs));
-
- rx_dcoffset #(.WIDTH(14),.ADDR(BASE+4)) rx_dcoffset_b
- (.clk(clk),.rst(rst),.set_stb(set_stb),.set_addr(set_addr),.set_data(set_data),
- .adc_in(adc_b),.adc_out(adc_b_ofs));
-
- wire [7:0] muxctrl;
- setting_reg #(.my_addr(BASE+5), .width(8)) sr_8
- (.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr),
- .in(set_data),.out(muxctrl),.changed());
-
- wire [1:0] gpio_ena;
- setting_reg #(.my_addr(BASE+6), .width(2)) sr_9
+ setting_reg #(.my_addr(BASE+3), .width(2)) sr_3
(.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr),
- .in(set_data),.out(gpio_ena),.changed());
+ .in(set_data),.out({realmode,swap_iq}),.changed());
- always @(posedge clk)
- case(muxctrl[3:0]) // The I mapping
- 0: adc_i <= adc_a_ofs;
- 1: adc_i <= adc_b_ofs;
- 2: adc_i <= 0;
- default: adc_i <= 0;
- endcase // case (muxctrl[3:0])
+ // MUX so we can do realmode signals on either input
always @(posedge clk)
- case(muxctrl[7:4]) // The Q mapping
- 0: adc_q <= adc_a_ofs;
- 1: adc_q <= adc_b_ofs;
- 2: adc_q <= 0;
- default: adc_q <= 0;
- endcase // case (muxctrl[7:4])
-
+ if(swap_iq)
+ begin
+ adc_i_mux <= adc_q;
+ adc_q_mux <= realmode ? 24'd0 : adc_i;
+ end
+ else
+ begin
+ adc_i_mux <= adc_i;
+ adc_q_mux <= realmode ? 24'd0 : adc_q;
+ end
+
+ // NCO
always @(posedge clk)
if(rst)
phase <= 0;
@@ -102,74 +88,55 @@ module dsp_core_rx
else
phase <= phase + phase_inc;
- MULT18X18S mult_i
- (.P(prod_i), // 36-bit multiplier output
- .A({{4{adc_i[13]}},adc_i} ), // 18-bit multiplier input
- .B({{2{scale_i[15]}},scale_i}), // 18-bit multiplier input
- .C(clk), // Clock input
- .CE(1), // Clock enable input
- .R(rst) // Synchronous reset input
- );
-
- MULT18X18S mult_q
- (.P(prod_q), // 36-bit multiplier output
- .A({{4{adc_q[13]}},adc_q} ), // 18-bit multiplier input
- .B({{2{scale_q[15]}},scale_q}), // 18-bit multiplier input
- .C(clk), // Clock input
- .CE(1), // Clock enable input
- .R(rst) // Synchronous reset input
- );
-
-
- cordic_z24 #(.bitwidth(24))
+ // CORDIC 24-bit I/O
+ cordic_z24 #(.bitwidth(25))
cordic(.clock(clk), .reset(rst), .enable(run),
- .xi(prod_i[23:0]),. yi(prod_q[23:0]), .zi(phase[31:8]),
+ .xi({adc_i_mux[23],adc_i_mux}),. yi({adc_q_mux[23],adc_q_mux}), .zi(phase[31:8]),
.xo(i_cordic),.yo(q_cordic),.zo() );
+ clip_reg #(.bits_in(25), .bits_out(24)) clip_i (.clk(clk), .in(i_cordic), .out(i_cordic_clip));
+ clip_reg #(.bits_in(25), .bits_out(24)) clip_q (.clk(clk), .in(q_cordic), .out(q_cordic_clip));
+
+ // CIC decimator 24 bit I/O
cic_strober cic_strober(.clock(clk),.reset(rst),.enable(run),.rate(cic_decim_rate),
.strobe_fast(1),.strobe_slow(strobe_cic) );
cic_decim #(.bw(24))
decim_i (.clock(clk),.reset(rst),.enable(run),
.rate(cic_decim_rate),.strobe_in(1'b1),.strobe_out(strobe_cic),
- .signal_in(i_cordic),.signal_out(i_cic));
+ .signal_in(i_cordic_clip),.signal_out(i_cic));
cic_decim #(.bw(24))
decim_q (.clock(clk),.reset(rst),.enable(run),
.rate(cic_decim_rate),.strobe_in(1'b1),.strobe_out(strobe_cic),
- .signal_in(q_cordic),.signal_out(q_cic));
+ .signal_in(q_cordic_clip),.signal_out(q_cic));
- round_reg #(.bits_in(24),.bits_out(18)) round_icic (.clk(clk),.in(i_cic),.out(i_cic_scaled));
- round_reg #(.bits_in(24),.bits_out(18)) round_qcic (.clk(clk),.in(q_cic),.out(q_cic_scaled));
- reg strobe_cic_d1;
- always @(posedge clk) strobe_cic_d1 <= strobe_cic;
-
- small_hb_dec #(.WIDTH(18)) small_hb_i
+ // First (small) halfband 24 bit I/O
+ small_hb_dec #(.WIDTH(24)) small_hb_i
(.clk(clk),.rst(rst),.bypass(~enable_hb1),.run(run),
- .stb_in(strobe_cic_d1),.data_in(i_cic_scaled),.stb_out(strobe_hb1),.data_out(i_hb1));
+ .stb_in(strobe_cic),.data_in(i_cic),.stb_out(strobe_hb1),.data_out(i_hb1));
- small_hb_dec #(.WIDTH(18)) small_hb_q
+ small_hb_dec #(.WIDTH(24)) small_hb_q
(.clk(clk),.rst(rst),.bypass(~enable_hb1),.run(run),
- .stb_in(strobe_cic_d1),.data_in(q_cic_scaled),.stb_out(),.data_out(q_hb1));
+ .stb_in(strobe_cic),.data_in(q_cic),.stb_out(),.data_out(q_hb1));
+ // Second (large) halfband 24 bit I/O
wire [8:0] cpi_hb = enable_hb1 ? {cic_decim_rate,1'b0} : {1'b0,cic_decim_rate};
- hb_dec #(.IWIDTH(18), .OWIDTH(18), .CWIDTH(18), .ACCWIDTH(24)) hb_i
+ hb_dec #(.WIDTH(24)) hb_i
(.clk(clk),.rst(rst),.bypass(~enable_hb2),.run(run),.cpi(cpi_hb),
.stb_in(strobe_hb1),.data_in(i_hb1),.stb_out(strobe_hb2),.data_out(i_hb2));
- hb_dec #(.IWIDTH(18), .OWIDTH(18), .CWIDTH(18), .ACCWIDTH(24)) hb_q
+ hb_dec #(.WIDTH(24)) hb_q
(.clk(clk),.rst(rst),.bypass(~enable_hb2),.run(run),.cpi(cpi_hb),
.stb_in(strobe_hb1),.data_in(q_hb1),.stb_out(),.data_out(q_hb2));
- round #(.bits_in(18),.bits_out(16)) round_iout (.in(i_hb2),.out(i_out));
- round #(.bits_in(18),.bits_out(16)) round_qout (.in(q_hb2),.out(q_out));
+ // Round final answer to 16 bits
+ round_sd #(.WIDTH_IN(24),.WIDTH_OUT(16)) round_i
+ (.clk(clk),.reset(rst), .in(i_hb2),.strobe_in(strobe_hb2), .out(sample[31:16]), .strobe_out(strobe));
- reg [31:0] sample_reg;
- always @(posedge clk)
- sample_reg <= {i_out,q_out};
+ round_sd #(.WIDTH_IN(24),.WIDTH_OUT(16)) round_q
+ (.clk(clk),.reset(rst), .in(q_hb2),.strobe_in(strobe_hb2), .out(sample[15:0]), .strobe_out());
- assign sample = sample_reg;
- assign strobe = strobe_hb2;
- assign debug = {enable_hb1, enable_hb2, run, strobe, strobe_cic, strobe_cic_d1, strobe_hb1, strobe_hb2};
+ assign debug = {enable_hb1, enable_hb2, run, strobe, strobe_cic, strobe_hb1, strobe_hb2};
endmodule // dsp_core_rx
diff --git a/fpga/usrp2/sdr_lib/dsp_core_rx_tb.v b/fpga/usrp2/sdr_lib/dsp_core_rx_tb.v
new file mode 100644
index 000000000..271db8cef
--- /dev/null
+++ b/fpga/usrp2/sdr_lib/dsp_core_rx_tb.v
@@ -0,0 +1,73 @@
+
+`timescale 1ns/1ns
+module dsp_core_rx_tb();
+
+ reg clk, rst;
+
+ initial rst = 1;
+ initial #1000 rst = 0;
+ initial clk = 0;
+ always #5 clk = ~clk;
+
+ initial $dumpfile("dsp_core_rx_tb.vcd");
+ initial $dumpvars(0,dsp_core_rx_tb);
+
+ reg signed [23:0] adc_in;
+ wire signed [15:0] adc_out_i, adc_out_q;
+
+ always @(posedge clk)
+ begin
+ $display(adc_in);
+ $display(adc_out_i);
+ $display(adc_out_q);
+ end
+
+ reg run;
+ reg set_stb;
+ reg [7:0] set_addr;
+ reg [31:0] set_data;
+
+ dsp_core_rx #(.BASE(0)) dsp_core_rx
+ (.clk(clk),.rst(rst),
+ .set_stb(set_stb),.set_addr(set_addr),.set_data(set_data),
+ .adc_i(adc_in), .adc_ovf_i(0),
+ .adc_q(0), .adc_ovf_q(0),
+ .sample({adc_out_i,adc_out_q}),
+ .run(run), .strobe(), .debug());
+
+ initial
+ begin
+ run <= 0;
+ @(negedge rst);
+ @(posedge clk);
+ set_addr <= 1;
+ set_data <= {16'd64,16'd64}; // set gains
+ set_stb <= 1;
+ @(posedge clk);
+ set_addr <= 2;
+ set_data <= {16'd0,8'd3,8'd1}; // set decim
+ set_stb <= 1;
+ @(posedge clk);
+ set_addr <= 0;
+ //set_data <= {32'h0000_0000};
+ set_data <= {32'h01CA_C083}; // 700 kHz
+ set_stb <= 1;
+ @(posedge clk);
+ set_stb <= 0;
+ @(posedge clk);
+ run <= 1;
+ end
+
+ always @(posedge clk)
+ //adc_in <= 24'd1000000;
+ adc_in <= 24'h80_0000;
+
+ /*
+ always @(posedge clk)
+ if(rst)
+ adc_in <= 0;
+ else
+ adc_in <= adc_in + 4;
+ //adc_in <= (($random % 473) + 23)/4;
+*/
+endmodule // dsp_core_rx_tb
diff --git a/fpga/usrp2/sdr_lib/dsp_core_tx.v b/fpga/usrp2/sdr_lib/dsp_core_tx.v
index 58bd82f6e..f02c63b42 100644
--- a/fpga/usrp2/sdr_lib/dsp_core_tx.v
+++ b/fpga/usrp2/sdr_lib/dsp_core_tx.v
@@ -21,8 +21,7 @@ module dsp_core_tx
(input clk, input rst,
input set_stb, input [7:0] set_addr, input [31:0] set_data,
- output reg [15:0] dac_a,
- output reg [15:0] dac_b,
+ output [23:0] tx_i, output [23:0] tx_q,
// To tx_control
input [31:0] sample,
@@ -50,10 +49,6 @@ module dsp_core_tx
(.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), .width(8)) sr_4
- (.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr),
- .in(set_data),.out({dacmux_b,dacmux_a}),.changed());
-
// Strobes are all now delayed by 1 cycle for timing reasons
wire strobe_cic_pre, strobe_hb1_pre, strobe_hb2_pre;
reg strobe_cic = 1;
@@ -148,20 +143,9 @@ module dsp_core_tx
.CE(1), // Clock enable input
.R(rst) // Synchronous reset input
);
-
- always @(posedge clk)
- case(dacmux_a)
- 0 : dac_a <= prod_i[28:13];
- 1 : dac_a <= prod_q[28:13];
- default : dac_a <= 0;
- endcase // case(dacmux_a)
-
- always @(posedge clk)
- case(dacmux_b)
- 0 : dac_b <= prod_i[28:13];
- 1 : dac_b <= prod_q[28:13];
- default : dac_b <= 0;
- endcase // case(dacmux_b)
+
+ assign tx_i = prod_i[28:5];
+ assign tx_q = prod_q[28:5];
assign debug = {strobe_cic, strobe_hb1, strobe_hb2,run};
diff --git a/fpga/usrp2/sdr_lib/hb_dec.v b/fpga/usrp2/sdr_lib/hb_dec.v
index 9747f0adb..8d21c21c0 100644
--- a/fpga/usrp2/sdr_lib/hb_dec.v
+++ b/fpga/usrp2/sdr_lib/hb_dec.v
@@ -22,17 +22,27 @@
// myfilt = round(2^18 * halfgen4(.7/4,8))
module hb_dec
- #(parameter IWIDTH=18, OWIDTH=18, CWIDTH=18, ACCWIDTH=24)
+ #(parameter WIDTH=24)
(input clk,
input rst,
input bypass,
input run,
input [8:0] cpi, // Clocks per input -- equal to the decimation ratio ahead of this block
input stb_in,
- input [IWIDTH-1:0] data_in,
+ input [WIDTH-1:0] data_in,
output reg stb_out,
- output reg [OWIDTH-1:0] data_out);
+ output reg [WIDTH-1:0] data_out);
+ localparam INTWIDTH = 17;
+ localparam ACCWIDTH = WIDTH + 3;
+
+ // Round off inputs to 17 bits because of 18 bit multipliers
+ wire [INTWIDTH-1:0] data_rnd;
+ wire stb_rnd;
+
+ round_sd #(.WIDTH_IN(WIDTH),.WIDTH_OUT(INTWIDTH)) round_in
+ (.clk(clk),.reset(rst),.in(data_in),.strobe_in(stb_in),.out(data_rnd),.strobe_out(stb_rnd));
+
// Control
reg [3:0] addr_odd_a, addr_odd_b, addr_odd_c, addr_odd_d;
wire write_odd, write_even, do_mult;
@@ -45,16 +55,16 @@ module hb_dec
always @(posedge clk)
if(rst | ~run)
odd <= 0;
- else if(stb_in)
+ else if(stb_rnd)
odd <= ~odd;
- assign write_odd = stb_in & odd;
- assign write_even = stb_in & ~odd;
+ assign write_odd = stb_rnd & odd;
+ assign write_even = stb_rnd & ~odd;
always @(posedge clk)
if(rst | ~run)
phase <= 0;
- else if(stb_in & odd)
+ else if(stb_rnd & odd)
phase <= 1;
else if(phase == 4)
phase <= 0;
@@ -69,7 +79,7 @@ module hb_dec
if(rst)
stb_out_pre <= 0;
else
- stb_out_pre <= {stb_out_pre[14:0],(stb_in & odd)};
+ stb_out_pre <= {stb_out_pre[14:0],(stb_rnd & odd)};
always @*
case(phase)
@@ -93,11 +103,12 @@ module hb_dec
assign clear = stb_out_pre[3];
// Data
- wire [IWIDTH-1:0] data_odd_a, data_odd_b, data_odd_c, data_odd_d;
- wire [IWIDTH-1:0] sum1, sum2;
- wire [OWIDTH-1:0] final_sum;
- reg [CWIDTH-1:0] coeff1, coeff2;
- wire [35:0] prod1, prod2;
+ wire [INTWIDTH-1:0] data_odd_a, data_odd_b, data_odd_c, data_odd_d;
+ reg [INTWIDTH:0] sum1, sum2; // these are 18-bit inputs to mult
+ reg [WIDTH:0] final_sum;
+ wire [WIDTH-1:0] final_sum_clip;
+ reg [17:0] coeff1, coeff2;
+ wire [35:0] prod1, prod2;
always @* // Outer coeffs
case(phase_d1)
@@ -117,19 +128,19 @@ module hb_dec
default : coeff2 = -6107;
endcase // case(phase)
- srl #(.WIDTH(IWIDTH)) srl_odd_a
- (.clk(clk),.write(write_odd),.in(data_in),.addr(addr_odd_a),.out(data_odd_a));
- srl #(.WIDTH(IWIDTH)) srl_odd_b
- (.clk(clk),.write(write_odd),.in(data_in),.addr(addr_odd_b),.out(data_odd_b));
- srl #(.WIDTH(IWIDTH)) srl_odd_c
- (.clk(clk),.write(write_odd),.in(data_in),.addr(addr_odd_c),.out(data_odd_c));
- srl #(.WIDTH(IWIDTH)) srl_odd_d
- (.clk(clk),.write(write_odd),.in(data_in),.addr(addr_odd_d),.out(data_odd_d));
-
- add2_reg /*_and_round_reg*/ #(.WIDTH(IWIDTH)) add1 (.clk(clk),.in1(data_odd_a),.in2(data_odd_b),.sum(sum1));
- add2_reg /*_and_round_reg*/ #(.WIDTH(IWIDTH)) add2 (.clk(clk),.in1(data_odd_c),.in2(data_odd_d),.sum(sum2));
-
- wire [IWIDTH-1:0] data_even;
+ srl #(.WIDTH(INTWIDTH)) srl_odd_a
+ (.clk(clk),.write(write_odd),.in(data_rnd),.addr(addr_odd_a),.out(data_odd_a));
+ srl #(.WIDTH(INTWIDTH)) srl_odd_b
+ (.clk(clk),.write(write_odd),.in(data_rnd),.addr(addr_odd_b),.out(data_odd_b));
+ srl #(.WIDTH(INTWIDTH)) srl_odd_c
+ (.clk(clk),.write(write_odd),.in(data_rnd),.addr(addr_odd_c),.out(data_odd_c));
+ srl #(.WIDTH(INTWIDTH)) srl_odd_d
+ (.clk(clk),.write(write_odd),.in(data_rnd),.addr(addr_odd_d),.out(data_odd_d));
+
+ always @(posedge clk) sum1 <= {data_odd_a[INTWIDTH-1],data_odd_a} + {data_odd_b[INTWIDTH-1],data_odd_b};
+ always @(posedge clk) sum2 <= {data_odd_c[INTWIDTH-1],data_odd_c} + {data_odd_d[INTWIDTH-1],data_odd_d};
+
+ wire [INTWIDTH-1:0] data_even;
reg [3:0] addr_even;
always @(posedge clk)
@@ -140,49 +151,39 @@ module hb_dec
default : addr_even <= 7;
endcase // case(cpi)
- srl #(.WIDTH(IWIDTH)) srl_even
- (.clk(clk),.write(write_even),.in(data_in),.addr(addr_even),.out(data_even));
-
- localparam MWIDTH = ACCWIDTH-2;
- wire [MWIDTH-1:0] sum_of_prod;
+ srl #(.WIDTH(INTWIDTH)) srl_even
+ (.clk(clk),.write(write_even),.in(data_rnd),.addr(addr_even),.out(data_even));
MULT18X18S mult1(.C(clk), .CE(do_mult), .R(rst), .P(prod1), .A(coeff1), .B(sum1) );
MULT18X18S mult2(.C(clk), .CE(do_mult), .R(rst), .P(prod2), .A(coeff2), .B(sum2) );
- add2_and_round_reg #(.WIDTH(MWIDTH))
- add3 (.clk(clk),.in1(prod1[35:36-MWIDTH]),.in2(prod2[35:36-MWIDTH]),.sum(sum_of_prod));
- wire [ACCWIDTH-1:0] acc_out;
+ reg [35:0] sum_of_prod;
+ always @(posedge clk) sum_of_prod <= prod1 + prod2; // Can't overflow
- acc #(.IWIDTH(MWIDTH),.OWIDTH(ACCWIDTH))
- acc (.clk(clk),.clear(clear),.acc(do_acc),.in(sum_of_prod),.out(acc_out));
+ wire [ACCWIDTH-1:0] acc_out;
+ acc #(.IWIDTH(ACCWIDTH-2),.OWIDTH(ACCWIDTH))
+ acc (.clk(clk),.clear(clear),.acc(do_acc),.in(sum_of_prod[35:38-ACCWIDTH]),.out(acc_out));
- localparam SHIFT_FACTOR = ACCWIDTH-IWIDTH-5;
wire [ACCWIDTH-1:0] data_even_signext;
- wire [ACCWIDTH:0] final_sum_unrounded;
- sign_extend #(.bits_in(IWIDTH),.bits_out(ACCWIDTH-SHIFT_FACTOR))
- signext_data_even (.in(data_even),.out(data_even_signext[ACCWIDTH-1:SHIFT_FACTOR]));
- assign data_even_signext[SHIFT_FACTOR-1:0] = 0;
+ localparam SHIFT_FACTOR = 6;
- add2_reg /* add2_and_round_reg */ #(.WIDTH(ACCWIDTH+1))
- final_adder (.clk(clk), .in1({acc_out,1'b0}), .in2({data_even_signext,1'b0}), .sum(final_sum_unrounded));
-
- round_reg #(.bits_in(ACCWIDTH-4),.bits_out(OWIDTH))
- final_round (.clk(clk),.in(final_sum_unrounded[ACCWIDTH-5:0]),.out(final_sum));
-
- // Output
- always @(posedge clk)
- if(bypass)
- data_out <= data_in;
- else if(stb_out_pre[9])
- data_out <= final_sum;
+ sign_extend #(.bits_in(INTWIDTH),.bits_out(ACCWIDTH-SHIFT_FACTOR)) signext_data_even
+ (.in(data_even),.out(data_even_signext[ACCWIDTH-1:SHIFT_FACTOR]));
+ assign data_even_signext[SHIFT_FACTOR-1:0] = 0;
+ always @(posedge clk) final_sum <= acc_out + data_even_signext;
+
+ clip #(.bits_in(WIDTH+1), .bits_out(WIDTH)) clip (.in(final_sum), .out(final_sum_clip));
+
+ // Output MUX to allow for bypass
+ wire selected_stb = bypass ? stb_in : stb_out_pre[8];
+
always @(posedge clk)
- if(rst)
- stb_out <= 0;
- else if(bypass)
- stb_out <= stb_in;
- else
- stb_out <= stb_out_pre[9];
-
+ begin
+ stb_out <= selected_stb;
+ if(selected_stb)
+ data_out <= bypass ? data_in : final_sum_clip;
+ end
+
endmodule // hb_dec
diff --git a/fpga/usrp2/sdr_lib/hb_dec_tb.v b/fpga/usrp2/sdr_lib/hb_dec_tb.v
index 256f6085d..153cfba76 100644
--- a/fpga/usrp2/sdr_lib/hb_dec_tb.v
+++ b/fpga/usrp2/sdr_lib/hb_dec_tb.v
@@ -18,7 +18,7 @@
module hb_dec_tb( ) ;
// Parameters for instantiation
- parameter clocks = 9'd2 ; // Number of clocks per input
+ parameter clocks = 9'd12 ; // Number of clocks per input
parameter decim = 1 ; // Sets the filter to decimate
parameter rate = 2 ; // Sets the decimation rate
@@ -26,9 +26,9 @@ module hb_dec_tb( ) ;
reg reset ;
reg enable ;
reg strobe_in ;
- reg signed [17:0] data_in ;
+ reg signed [23:0] data_in ;
wire strobe_out ;
- wire signed [17:0] data_out ;
+ wire signed [23:0] data_out ;
initial
begin
@@ -65,8 +65,8 @@ module hb_dec_tb( ) ;
*/
- hb_dec #(.IWIDTH(18),.OWIDTH(18),.CWIDTH(18),.ACCWIDTH(24)) uut
- (.clk(clock),.rst(reset),.bypass(0),.cpi(clocks),.stb_in(strobe_in),.data_in(data_in),
+ hb_dec #(.WIDTH(24)) uut
+ (.clk(clock),.rst(reset),.bypass(0),.run(1),.cpi(clocks),.stb_in(strobe_in),.data_in(data_in),
.stb_out(strobe_out),.data_out(data_out) );
integer i, ri, ro, infile, outfile ;
diff --git a/fpga/usrp2/sdr_lib/input.dat b/fpga/usrp2/sdr_lib/input.dat
index 1e649ac2e..85b5887e8 100644
--- a/fpga/usrp2/sdr_lib/input.dat
+++ b/fpga/usrp2/sdr_lib/input.dat
@@ -6,7 +6,6 @@
0
0
0
--131072
0
0
0
@@ -16,6 +15,7 @@
0
0
0
+8388607
0
0
0
@@ -38,34 +38,6 @@
0
0
0
--131072
--131072
--131072
--131072
--131072
--131072
--131072
--131072
--131072
--131072
--131072
--131072
--131072
--131072
--131072
--131072
--131072
--131072
--131072
--131072
--131072
--131072
--131072
--131072
--131072
--131072
--131072
--131072
0
0
0
@@ -82,6 +54,7 @@
0
0
0
+8388607
0
0
0
@@ -96,200 +69,6 @@
0
0
0
-131071
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-131071
-131071
-131071
-131071
-131071
-131071
-131071
-131071
-131071
-131071
-131071
-131071
-131071
-131071
-131071
-131071
-131071
-131071
-131071
-131071
-131071
-131071
-131071
-131071
-131071
-131071
-131071
-131071
-131071
-131071
-131071
-131071
-131071
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-100000
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
--131072
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
-0
--131072
--131072
--131072
--131072
--131072
--131072
--131072
--131072
--131072
--131072
--131072
--131072
--131072
--131072
--131072
--131072
--131072
--131072
--131072
--131072
--131072
--131072
--131072
--131072
--131072
--131072
--131072
--131072
--131072
--131072
--131072
--131072
--131072
--131072
--131072
--131072
--131072
--131072
--131072
--131072
--131072
--131072
-0
-0
0
0
0
@@ -313,6 +92,56 @@
0
0
0
+8388607
+8388607
+8388607
+8388607
+8388607
+8388607
+8388607
+8388607
+8388607
+8388607
+8388607
+8388607
+8388607
+8388607
+8388607
+8388607
+8388607
+8388607
+8388607
+8388607
+8388607
+8388607
+8388607
+8388607
+8388607
+8388607
+8388607
+8388607
+8388607
+8388607
+8388607
+8388607
+8388607
+8388607
+8388607
+8388607
+8388607
+8388607
+8388607
+8388607
+8388607
+8388607
+8388607
+8388607
+8388607
+8388607
+8388607
+8388607
+8388607
+8388607
0
0
0
@@ -339,3 +168,4 @@
0
0
0
+
diff --git a/fpga/usrp2/sdr_lib/round.v b/fpga/usrp2/sdr_lib/round.v
index c4f9ec9cd..7a137d702 100644
--- a/fpga/usrp2/sdr_lib/round.v
+++ b/fpga/usrp2/sdr_lib/round.v
@@ -26,8 +26,10 @@ module round
#(parameter bits_in=0,
parameter bits_out=0)
(input [bits_in-1:0] in,
- output [bits_out-1:0] out);
+ output [bits_out-1:0] out,
+ output [bits_in-bits_out:0] err);
assign out = in[bits_in-1:bits_in-bits_out] + (in[bits_in-1] & |in[bits_in-bits_out-1:0]);
+ assign err = in - {out,{(bits_in-bits_out){1'b0}}};
endmodule // round
diff --git a/fpga/usrp2/sdr_lib/round_reg.v b/fpga/usrp2/sdr_lib/round_reg.v
index aa0972dab..6f2e974d7 100644
--- a/fpga/usrp2/sdr_lib/round_reg.v
+++ b/fpga/usrp2/sdr_lib/round_reg.v
@@ -27,13 +27,18 @@ module round_reg
parameter bits_out=0)
(input clk,
input [bits_in-1:0] in,
- output reg [bits_out-1:0] out);
+ output reg [bits_out-1:0] out,
+ output reg [bits_in-bits_out:0] err);
wire [bits_out-1:0] temp;
-
- round #(.bits_in(bits_in),.bits_out(bits_out)) round (.in(in),.out(temp));
+ wire [bits_in-bits_out:0] err_temp;
+
+ round #(.bits_in(bits_in),.bits_out(bits_out)) round (.in(in),.out(temp), .err(err_temp));
always @(posedge clk)
out <= temp;
+
+ always @(posedge clk)
+ err <= err_temp;
-endmodule // round
+endmodule // round_reg
diff --git a/fpga/usrp2/sdr_lib/round_sd.v b/fpga/usrp2/sdr_lib/round_sd.v
new file mode 100644
index 000000000..aeeb3502f
--- /dev/null
+++ b/fpga/usrp2/sdr_lib/round_sd.v
@@ -0,0 +1,22 @@
+
+
+module round_sd
+ #(parameter WIDTH_IN=18,
+ parameter WIDTH_OUT=16)
+ (input clk, input reset,
+ input [WIDTH_IN-1:0] in, input strobe_in,
+ output [WIDTH_OUT-1:0] out, output strobe_out);
+
+ localparam ERR_WIDTH = WIDTH_IN - WIDTH_OUT + 1;
+
+ wire [ERR_WIDTH-1:0] err;
+ wire [WIDTH_IN-1:0] err_ext, sum;
+
+ sign_extend #(.bits_in(ERR_WIDTH),.bits_out(WIDTH_IN)) ext_err (.in(err), .out(err_ext));
+
+ add2_and_clip_reg #(.WIDTH(WIDTH_IN)) add2_and_clip_reg
+ (.clk(clk), .rst(reset), .in1(in), .in2(err_ext), .strobe_in(strobe_in), .sum(sum), .strobe_out(strobe_out));
+
+ round #(.bits_in(WIDTH_IN),.bits_out(WIDTH_OUT)) round_sum (.in(sum), .out(out), .err(err));
+
+endmodule // round_sd
diff --git a/fpga/usrp2/sdr_lib/round_sd_tb.v b/fpga/usrp2/sdr_lib/round_sd_tb.v
new file mode 100644
index 000000000..1e8e9a323
--- /dev/null
+++ b/fpga/usrp2/sdr_lib/round_sd_tb.v
@@ -0,0 +1,58 @@
+
+module round_sd_tb();
+
+ reg clk, rst;
+
+ initial rst = 1;
+ initial #1000 rst = 0;
+ initial clk = 0;
+ always #5 clk = ~clk;
+
+ initial $dumpfile("round_sd_tb.vcd");
+ initial $dumpvars(0,round_sd_tb);
+
+ localparam WIDTH_IN = 8;
+ localparam WIDTH_OUT = 5;
+
+ reg [WIDTH_IN-1:0] adc_in, adc_in_del;
+ wire [WIDTH_OUT-1:0] adc_out;
+
+ integer factor = 1<<(WIDTH_IN-WIDTH_OUT);
+
+ always @(posedge clk)
+ if(~rst)
+ begin
+ if(adc_in_del[WIDTH_IN-1])
+ $write("-%d\t",-adc_in_del);
+ else
+ $write("%d\t",adc_in_del);
+ if(adc_out[WIDTH_OUT-1])
+ $write("-%d\t",-adc_out);
+ else
+ $write("%d\t",adc_out);
+ $write("\n");
+
+ //$write("%f\t",adc_in_del/factor);
+ //$write("%f\n",adc_in_del/factor-adc_out);
+ end
+
+ round_sd #(.WIDTH_IN(WIDTH_IN),.WIDTH_OUT(WIDTH_OUT))
+ round_sd(.clk(clk),.reset(rst), .in(adc_in), .strobe_in(1'b1), .out(adc_out), .strobe_out());
+
+ reg [5:0] counter = 0;
+
+ always @(posedge clk)
+ counter <= counter+1;
+
+ always @(posedge clk)
+ adc_in_del <= adc_in;
+
+ always @(posedge clk)
+ if(rst)
+ adc_in <= 0;
+ else if(counter == 63)
+ adc_in <= adc_in + 1;
+
+ initial #300000 $finish;
+
+endmodule // longfifo_tb
diff --git a/fpga/usrp2/sdr_lib/rx_dcoffset.v b/fpga/usrp2/sdr_lib/rx_dcoffset.v
index 64ff4110d..e43461261 100644
--- a/fpga/usrp2/sdr_lib/rx_dcoffset.v
+++ b/fpga/usrp2/sdr_lib/rx_dcoffset.v
@@ -18,43 +18,40 @@
module rx_dcoffset
- #(parameter WIDTH=14,
- parameter ADDR=8'd0)
- (input clk, input rst,
- input set_stb, input [7:0] set_addr, input [31:0] set_data,
- input signed [WIDTH-1:0] adc_in, output signed [WIDTH-1:0] adc_out);
-
- // Because of some extra delays to make timing easier, the transfer function is:
- // (z-1)/(z^2-z-alpha) where alpha is 1/2^n
+ #(parameter WIDTH=16,
+ parameter ADDR=8'd0,
+ parameter alpha_shift=16)
+ (input clk, input rst,
+ input set_stb, input [7:0] set_addr, input [31:0] set_data,
+ input [WIDTH-1:0] in, output [WIDTH-1:0] out);
- wire set_now = set_stb & (ADDR == set_addr);
+ wire set_now = set_stb & (ADDR == set_addr);
- reg fixed; // uses fixed offset
- wire signed [WIDTH-1:0] fixed_dco;
- reg signed [31:0] integrator;
+ reg fixed; // uses fixed offset
+ wire [WIDTH-1:0] fixed_dco;
+
+ localparam int_width = WIDTH + alpha_shift;
+ reg [int_width-1:0] integrator;
+ wire [WIDTH-1:0] quantized;
always @(posedge clk)
if(rst)
begin
fixed <= 0;
- integrator <= 32'd0;
+ integrator <= {int_width{1'b0}};
end
else if(set_now)
begin
- integrator <= {set_data[WIDTH-1:0],{(32-WIDTH){1'b0}}};
+ //integrator <= {set_data[30:0],{(31-int_width){1'b0}}};
fixed <= set_data[31];
end
else if(~fixed)
- integrator <= integrator + adc_out;
-
- wire [WIDTH:0] scaled_integrator;
-
- round #(.bits_in(33),.bits_out(15)) round (.in({integrator[31],integrator}),.out(scaled_integrator));
-
- wire [WIDTH:0] adc_out_int = {adc_in[WIDTH-1],adc_in} - scaled_integrator;
+ integrator <= integrator + {{(alpha_shift){out[WIDTH-1]}},out};
- clip_reg #(.bits_in(WIDTH+1),.bits_out(WIDTH)) clip_adc
- (.clk(clk),.in(adc_out_int),.out(adc_out));
+ round_sd #(.WIDTH_IN(int_width),.WIDTH_OUT(WIDTH)) round_sd
+ (.clk(clk), .reset(rst), .in(integrator), .strobe_in(1'b1), .out(quantized), .strobe_out());
+ add2_and_clip_reg #(.WIDTH(WIDTH)) add2_and_clip_reg
+ (.clk(clk), .rst(rst), .in1(in), .in2(-quantized), .strobe_in(1'b1), .sum(out), .strobe_out());
endmodule // rx_dcoffset
diff --git a/fpga/usrp2/sdr_lib/rx_dcoffset_tb.v b/fpga/usrp2/sdr_lib/rx_dcoffset_tb.v
index b0dd8cb05..b4fb66ad7 100644
--- a/fpga/usrp2/sdr_lib/rx_dcoffset_tb.v
+++ b/fpga/usrp2/sdr_lib/rx_dcoffset_tb.v
@@ -29,14 +29,26 @@ module rx_dcoffset_tb();
initial $dumpfile("rx_dcoffset_tb.vcd");
initial $dumpvars(0,rx_dcoffset_tb);
- reg [13:0] adc_in = 7;
+ reg [13:0] adc_in;
wire [13:0] adc_out;
always @(posedge clk)
- $display("%d\t%d",adc_in,adc_out);
+ begin
+ if(adc_in[13])
+ $write("-%d,",-adc_in);
+ else
+ $write("%d,",adc_in);
+ if(adc_out[13])
+ $write("-%d\n",-adc_out);
+ else
+ $write("%d\n",adc_out);
+ end
- rx_dcoffset #(.WIDTH(14),.ADDR(0))
+ rx_dcoffset #(.WIDTH(14),.ADDR(0), .alpha_shift(8))
rx_dcoffset(.clk(clk),.rst(rst),.set_stb(0),.set_addr(0),.set_data(0),
- .adc_in(adc_in),.adc_out(adc_out));
+ .in(adc_in),.out(adc_out));
+
+ always @(posedge clk)
+ adc_in <= (($random % 473) + 23)/4;
endmodule // longfifo_tb
diff --git a/fpga/usrp2/sdr_lib/rx_frontend.v b/fpga/usrp2/sdr_lib/rx_frontend.v
new file mode 100644
index 000000000..04b14787e
--- /dev/null
+++ b/fpga/usrp2/sdr_lib/rx_frontend.v
@@ -0,0 +1,73 @@
+
+module rx_frontend
+ #(parameter BASE = 0)
+ (input clk, input rst,
+ input set_stb, input [7:0] set_addr, input [31:0] set_data,
+
+ input [15:0] adc_a, input adc_ovf_a,
+ input [15:0] adc_b, input adc_ovf_b,
+
+ output [23:0] i_out, output [23:0] q_out,
+ input run,
+ output [31:0] debug
+ );
+
+ reg [15:0] adc_i, adc_q;
+ wire [17:0] adc_i_ofs, adc_q_ofs;
+ wire [35:0] corr_i, corr_q; wire [17:0] mag_corr,phase_corr;
+ wire swap_iq;
+ wire [23:0] i_final, q_final;
+
+ setting_reg #(.my_addr(BASE), .width(1)) sr_8
+ (.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr),
+ .in(set_data),.out(swap_iq),.changed());
+
+ always @(posedge clk)
+ if(swap_iq) // Swap
+ {adc_i,adc_q} <= {adc_b,adc_a};
+ else
+ {adc_i,adc_q} <= {adc_a,adc_b};
+
+ setting_reg #(.my_addr(BASE+1),.width(18)) sr_1
+ (.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr),
+ .in(set_data),.out(mag_corr),.changed());
+
+ setting_reg #(.my_addr(BASE+2),.width(18)) sr_2
+ (.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr),
+ .in(set_data),.out(phase_corr),.changed());
+
+ rx_dcoffset #(.WIDTH(18),.ADDR(BASE+3)) rx_dcoffset_i
+ (.clk(clk),.rst(rst),.set_stb(set_stb),.set_addr(set_addr),.set_data(set_data),
+ .in({adc_i,2'b00}),.out(adc_i_ofs));
+
+ rx_dcoffset #(.WIDTH(18),.ADDR(BASE+4)) rx_dcoffset_q
+ (.clk(clk),.rst(rst),.set_stb(set_stb),.set_addr(set_addr),.set_data(set_data),
+ .in({adc_q,2'b00}),.out(adc_q_ofs));
+
+ MULT18X18S mult_mag_corr
+ (.P(corr_i), .A(adc_i_ofs), .B(mag_corr), .C(clk), .CE(1), .R(rst) );
+
+ MULT18X18S mult_phase_corr
+ (.P(corr_q), .A(adc_i_ofs), .B(phase_corr), .C(clk), .CE(1), .R(rst) );
+
+ add2_and_clip_reg #(.WIDTH(24)) add_clip_i
+ (.clk(clk), .rst(rst),
+ .in1({adc_i_ofs,6'd0}), .in2({{4{corr_i[35]}},corr_i[35:16]}), .strobe_in(1'b1),
+ .sum(i_final), .strobe_out());
+
+ add2_and_clip_reg #(.WIDTH(24)) add_clip_q
+ (.clk(clk), .rst(rst),
+ .in1({adc_q_ofs,6'd0}), .in2({{4{corr_q[35]}},corr_q[35:16]}), .strobe_in(1'b1),
+ .sum(q_final), .strobe_out());
+
+ assign i_out = i_final;
+ assign q_out = q_final;
+
+ /*
+ round_sd #(.WIDTH_IN(24),.WIDTH_OUT(18)) round_i
+ (.clk(clk), .reset(rst), .in(i_final), .strobe_in(1'b1), .out(i_out), .strobe_out());
+
+ round_sd #(.WIDTH_IN(24),.WIDTH_OUT(18)) round_q
+ (.clk(clk), .reset(rst), .in(q_final), .strobe_in(1'b1), .out(q_out), .strobe_out());
+ */
+endmodule // rx_frontend
diff --git a/fpga/usrp2/sdr_lib/rx_frontend_tb.v b/fpga/usrp2/sdr_lib/rx_frontend_tb.v
new file mode 100644
index 000000000..487b72687
--- /dev/null
+++ b/fpga/usrp2/sdr_lib/rx_frontend_tb.v
@@ -0,0 +1,45 @@
+
+`timescale 1ns/1ns
+module rx_frontend_tb();
+
+ reg clk, rst;
+
+ initial rst = 1;
+ initial #1000 rst = 0;
+ initial clk = 0;
+ always #5 clk = ~clk;
+
+ initial $dumpfile("rx_frontend_tb.vcd");
+ initial $dumpvars(0,rx_frontend_tb);
+
+ reg [15:0] adc_in;
+ wire [17:0] adc_out;
+
+ always @(posedge clk)
+ begin
+ if(adc_in[13])
+ $write("-%d,",-adc_in);
+ else
+ $write("%d,",adc_in);
+ if(adc_out[13])
+ $write("-%d\n",-adc_out);
+ else
+ $write("%d\n",adc_out);
+ end
+
+ rx_frontend #(.BASE(0)) rx_frontend
+ (.clk(clk),.rst(rst),
+ .set_stb(0),.set_addr(0),.set_data(0),
+ .adc_a(adc_in), .adc_ovf_a(0),
+ .adc_b(0), .adc_ovf_b(0),
+ .i_out(adc_out),.q_out(),
+ .run(), .debug());
+
+ always @(posedge clk)
+ if(rst)
+ adc_in <= 0;
+ else
+ adc_in <= adc_in + 4;
+ //adc_in <= (($random % 473) + 23)/4;
+
+endmodule // rx_frontend_tb
diff --git a/fpga/usrp2/sdr_lib/small_hb_dec.v b/fpga/usrp2/sdr_lib/small_hb_dec.v
index 151b8c287..a7f93e056 100644
--- a/fpga/usrp2/sdr_lib/small_hb_dec.v
+++ b/fpga/usrp2/sdr_lib/small_hb_dec.v
@@ -29,21 +29,30 @@ module small_hb_dec
input stb_in,
input [WIDTH-1:0] data_in,
output reg stb_out,
- output [WIDTH-1:0] data_out);
+ output reg [WIDTH-1:0] data_out);
- reg stb_in_d1;
- reg [WIDTH-1:0] data_in_d1;
- always @(posedge clk) stb_in_d1 <= stb_in;
- always @(posedge clk) data_in_d1 <= data_in;
+ // Round off inputs to 17 bits because of 18 bit multipliers
+ localparam INTWIDTH = 17;
+ wire [INTWIDTH-1:0] data_rnd;
+ wire stb_rnd;
+
+ round_sd #(.WIDTH_IN(WIDTH),.WIDTH_OUT(INTWIDTH)) round_in
+ (.clk(clk),.reset(rst),.in(data_in),.strobe_in(stb_in),.out(data_rnd),.strobe_out(stb_rnd));
+
+
+ reg stb_rnd_d1;
+ reg [INTWIDTH-1:0] data_rnd_d1;
+ always @(posedge clk) stb_rnd_d1 <= stb_rnd;
+ always @(posedge clk) data_rnd_d1 <= data_rnd;
wire go;
reg phase, go_d1, go_d2, go_d3, go_d4;
always @(posedge clk)
if(rst | ~run)
phase <= 0;
- else if(stb_in_d1)
+ else if(stb_rnd_d1)
phase <= ~phase;
- assign go = stb_in_d1 & phase;
+ assign go = stb_rnd_d1 & phase;
always @(posedge clk)
if(rst | ~run)
begin
@@ -63,11 +72,11 @@ module small_hb_dec
wire [17:0] coeff_a = -10690;
wire [17:0] coeff_b = 75809;
- reg [WIDTH-1:0] d1, d2, d3, d4 , d5, d6;
+ reg [INTWIDTH-1:0] d1, d2, d3, d4 , d5, d6;
always @(posedge clk)
- if(stb_in_d1 | rst)
+ if(stb_rnd_d1 | rst)
begin
- d1 <= data_in_d1;
+ d1 <= data_rnd_d1;
d2 <= d1;
d3 <= d2;
d4 <= d3;
@@ -76,16 +85,14 @@ module small_hb_dec
end
reg [17:0] sum_a, sum_b, middle, middle_d1;
- wire [17:0] sum_a_unreg, sum_b_unreg;
- add2 #(.WIDTH(18)) add2_a (.in1(data_in_d1),.in2(d6),.sum(sum_a_unreg));
- add2 #(.WIDTH(18)) add2_b (.in1(d2),.in2(d4),.sum(sum_b_unreg));
-
+
always @(posedge clk)
if(go)
begin
- sum_a <= sum_a_unreg;
- sum_b <= sum_b_unreg;
- middle <= d3;
+ sum_a <= {data_rnd_d1[INTWIDTH-1],data_rnd_d1} + {d6[INTWIDTH-1],d6};
+ sum_b <= {d2[INTWIDTH-1],d2} + {d4[INTWIDTH-1],d4};
+ //middle <= {d3[INTWIDTH-1],d3};
+ middle <= {d3,1'b0};
end
always @(posedge clk)
@@ -106,23 +113,22 @@ module small_hb_dec
else if(go_d3)
accum <= accum + {prod};
- wire [17:0] accum_rnd;
- round #(.bits_in(36),.bits_out(18)) round_acc (.in(accum),.out(accum_rnd));
+ wire [WIDTH:0] accum_rnd;
+ wire [WIDTH-1:0] accum_rnd_clip;
+
+ wire stb_round;
+
+ round_sd #(.WIDTH_IN(36),.WIDTH_OUT(WIDTH+1)) round_acc
+ (.clk(clk), .reset(rst), .in(accum), .strobe_in(go_d4), .out(accum_rnd), .strobe_out(stb_round));
- reg [17:0] final_sum;
+ clip #(.bits_in(WIDTH+1),.bits_out(WIDTH)) clip (.in(accum_rnd), .out(accum_rnd_clip));
+
+ // Output
always @(posedge clk)
- if(bypass)
- final_sum <= data_in_d1;
- else if(go_d4)
- final_sum <= accum_rnd;
+ begin
+ stb_out <= bypass ? stb_in : stb_round;
+ data_out <= bypass ? data_in : accum_rnd_clip;
+ end
- assign data_out = final_sum;
- always @(posedge clk)
- if(rst)
- stb_out <= 0;
- else if(bypass)
- stb_out <= stb_in_d1;
- else
- stb_out <= go_d4;
endmodule // small_hb_dec
diff --git a/fpga/usrp2/sdr_lib/tx_frontend.v b/fpga/usrp2/sdr_lib/tx_frontend.v
new file mode 100644
index 000000000..d8525dd25
--- /dev/null
+++ b/fpga/usrp2/sdr_lib/tx_frontend.v
@@ -0,0 +1,86 @@
+
+module tx_frontend
+ #(parameter BASE=0,
+ parameter WIDTH_OUT=16)
+ (input clk, input rst,
+ input set_stb, input [7:0] set_addr, input [31:0] set_data,
+ input [23:0] tx_i, input [23:0] tx_q, input run,
+ output reg [WIDTH_OUT-1:0] dac_a, output reg [WIDTH_OUT-1:0] dac_b
+ );
+
+ // IQ balance --> DC offset --> rounding --> mux
+
+ wire [23:0] i_dco, q_dco, i_ofs, q_ofs;
+ wire [WIDTH_OUT-1:0] i_final, q_final;
+ wire [7:0] mux_ctrl;
+ wire [35:0] corr_i, corr_q;
+ wire [23:0] i_bal, q_bal;
+ wire [17:0] mag_corr, phase_corr;
+
+ setting_reg #(.my_addr(BASE+0), .width(24)) sr_0
+ (.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr),
+ .in(set_data),.out(i_dco),.changed());
+
+ setting_reg #(.my_addr(BASE+1), .width(24)) sr_1
+ (.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr),
+ .in(set_data),.out(q_dco),.changed());
+
+ setting_reg #(.my_addr(BASE+2),.width(18)) sr_2
+ (.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr),
+ .in(set_data),.out(mag_corr),.changed());
+
+ setting_reg #(.my_addr(BASE+3),.width(18)) sr_3
+ (.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr),
+ .in(set_data),.out(phase_corr),.changed());
+
+ setting_reg #(.my_addr(BASE+4), .width(8)) sr_4
+ (.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr),
+ .in(set_data),.out(mux_ctrl),.changed());
+
+ // IQ Balance
+ MULT18X18S mult_mag_corr
+ (.P(corr_i), .A(tx_i[23:6]), .B(mag_corr), .C(clk), .CE(1), .R(rst) );
+
+ MULT18X18S mult_phase_corr
+ (.P(corr_q), .A(tx_i[23:6]), .B(phase_corr), .C(clk), .CE(1), .R(rst) );
+
+ add2_and_clip_reg #(.WIDTH(24)) add_clip_i
+ (.clk(clk), .rst(rst),
+ .in1(tx_i), .in2({{4{corr_i[35]}},corr_i[35:16]}), .strobe_in(1'b1),
+ .sum(i_bal), .strobe_out());
+
+ add2_and_clip_reg #(.WIDTH(24)) add_clip_q
+ (.clk(clk), .rst(rst),
+ .in1(tx_q), .in2({{4{corr_q[35]}},corr_q[35:16]}), .strobe_in(1'b1),
+ .sum(q_bal), .strobe_out());
+
+ // DC Offset
+ add2_and_clip_reg #(.WIDTH(24)) add_dco_i
+ (.clk(clk), .rst(rst), .in1(i_dco), .in2(i_bal), .strobe_in(1'b1), .sum(i_ofs), .strobe_out());
+
+ add2_and_clip_reg #(.WIDTH(24)) add_dco_q
+ (.clk(clk), .rst(rst), .in1(q_dco), .in2(q_bal), .strobe_in(1'b1), .sum(q_ofs), .strobe_out());
+
+ // Rounding
+ round_sd #(.WIDTH_IN(24),.WIDTH_OUT(WIDTH_OUT)) round_i
+ (.clk(clk), .reset(rst), .in(i_ofs),.strobe_in(1'b1), .out(i_final), .strobe_out());
+
+ round_sd #(.WIDTH_IN(24),.WIDTH_OUT(WIDTH_OUT)) round_q
+ (.clk(clk), .reset(rst), .in(q_ofs),.strobe_in(1'b1), .out(q_final), .strobe_out());
+
+ // Mux
+ always @(posedge clk)
+ case(mux_ctrl[3:0])
+ 0 : dac_a <= i_final;
+ 1 : dac_a <= q_final;
+ default : dac_a <= 0;
+ endcase // case (mux_ctrl[3:0])
+
+ always @(posedge clk)
+ case(mux_ctrl[7:4])
+ 0 : dac_b <= i_final;
+ 1 : dac_b <= q_final;
+ default : dac_b <= 0;
+ endcase // case (mux_ctrl[7:4])
+
+endmodule // tx_frontend
diff --git a/fpga/usrp2/top/B100/u1plus_core.v b/fpga/usrp2/top/B100/u1plus_core.v
index 8a02f0fb8..4683f653c 100644
--- a/fpga/usrp2/top/B100/u1plus_core.v
+++ b/fpga/usrp2/top/B100/u1plus_core.v
@@ -30,7 +30,6 @@ module u1plus_core
output sclk, output [15:0] sen, output mosi, input miso,
input cgen_st_status, input cgen_st_ld, input cgen_st_refmon, output cgen_sync_b, output cgen_ref_sel,
- output tx_underrun, output rx_overrun,
inout [15:0] io_tx, inout [15:0] io_rx,
output [13:0] tx_i, output [13:0] tx_q,
input [11:0] rx_i, input [11:0] rx_q,
@@ -41,24 +40,31 @@ module u1plus_core
localparam RXFIFOSIZE = 11;
// 64 total regs in address space
- localparam SR_RX_CTRL = 0; // 9 regs (+0 to +8)
- localparam SR_RX_DSP = 16; // 7 regs (+0 to +6)
- localparam SR_TX_CTRL = 24; // 6 regs (+0 to +5)
- localparam SR_TX_DSP = 32; // 5 regs (+0 to +4)
- localparam SR_TIME64 = 40; // 6 regs (+0 to +5)
- localparam SR_CLEAR_RX_FIFO = 48; // 1 reg
- localparam SR_CLEAR_TX_FIFO = 49; // 1 reg
- localparam SR_GLOBAL_RESET = 50; // 1 reg
- localparam SR_REG_TEST32 = 52; // 1 reg
-
- wire [7:0] COMPAT_NUM = 8'd3;
+ localparam SR_RX_CTRL0 = 0; // 9 regs (+0 to +8)
+ localparam SR_RX_DSP0 = 10; // 4 regs (+0 to +3)
+ localparam SR_RX_CTRL1 = 16; // 9 regs (+0 to +8)
+ localparam SR_RX_DSP1 = 26; // 4 regs (+0 to +3)
+ localparam SR_TX_CTRL = 32; // 4 regs (+0 to +3)
+ localparam SR_TX_DSP = 38; // 3 regs (+0 to +2)
+
+ localparam SR_TIME64 = 42; // 6 regs (+0 to +5)
+ localparam SR_RX_FRONT = 48; // 5 regs (+0 to +4)
+ localparam SR_TX_FRONT = 54; // 5 regs (+0 to +4)
+
+ localparam SR_REG_TEST32 = 60; // 1 reg
+ localparam SR_CLEAR_RX_FIFO = 61; // 1 reg
+ localparam SR_CLEAR_TX_FIFO = 62; // 1 reg
+ localparam SR_GLOBAL_RESET = 63; // 1 reg
+
+ wire [7:0] COMPAT_NUM = 8'd5;
wire wb_clk = clk_fpga;
wire wb_rst, global_reset;
wire pps_int;
wire [63:0] vita_time, vita_time_pps;
- reg [15:0] reg_leds, reg_cgen_ctrl, reg_test, xfer_rate;
+ reg [15:0] reg_leds, reg_cgen_ctrl, reg_test;
+ wire [15:0] xfer_rate = 0;
wire [7:0] test_rate;
wire [3:0] test_ctrl;
@@ -72,11 +78,11 @@ module u1plus_core
wire [31:0] debug_vt;
wire gpif_rst;
- wire rx_overrun_dsp, rx_overrun_gpmc, tx_underrun_dsp, tx_underrun_gpmc;
reg [7:0] frames_per_packet;
- assign rx_overrun = rx_overrun_gpmc | rx_overrun_dsp;
- assign tx_underrun = tx_underrun_gpmc | tx_underrun_dsp;
+ wire rx_overrun_dsp0, rx_overrun_dsp1, rx_overrun_gpif, tx_underrun_dsp, tx_underrun_gpif;
+ wire rx_overrun = rx_overrun_gpif | rx_overrun_dsp0 | rx_overrun_dsp1;
+ wire tx_underrun = tx_underrun_gpif | tx_underrun_dsp;
setting_reg #(.my_addr(SR_GLOBAL_RESET), .width(1)) sr_reset
(.clk(wb_clk),.rst(wb_rst),.strobe(set_stb),.addr(set_addr),
@@ -97,13 +103,12 @@ module u1plus_core
wire [sw-1:0] m0_sel;
wire m0_cyc, m0_stb, m0_we, m0_ack, m0_err, m0_rty;
- wire [31:0] debug_gpmc;
+ wire [31:0] debug_gpif;
wire [35:0] tx_data, rx_data, tx_err_data;
wire tx_src_rdy, tx_dst_rdy, rx_src_rdy, rx_dst_rdy,
tx_err_src_rdy, tx_err_dst_rdy;
- wire bus_error;
wire clear_tx, clear_rx;
setting_reg #(.my_addr(SR_CLEAR_RX_FIFO), .width(1)) sr_clear_rx
@@ -128,36 +133,83 @@ module u1plus_core
.rx_data_i(rx_data), .rx_src_rdy_i(rx_src_rdy), .rx_dst_rdy_o(rx_dst_rdy),
.tx_err_data_i(tx_err_data), .tx_err_src_rdy_i(tx_err_src_rdy), .tx_err_dst_rdy_o(tx_err_dst_rdy),
- .tx_underrun(tx_underrun_gpmc), .rx_overrun(rx_overrun_gpmc),
+ .tx_underrun(tx_underrun_gpif), .rx_overrun(rx_overrun_gpif),
.frames_per_packet(frames_per_packet), .test_len(test_len), .test_rate(test_rate), .test_ctrl(test_ctrl),
.debug0(debug0), .debug1(debug1));
// /////////////////////////////////////////////////////////////////////////
- // DSP RX
- wire [31:0] sample_rx;
- wire strobe_rx, run_rx;
- wire [31:0] debug_rx_dsp, vr_debug;
+ // RX ADC Frontend, does IQ Balance, DC Offset, muxing
+
+ wire [23:0] adc_i, adc_q; // 24 bits is total overkill here, but it matches u2/u2p
+ wire run_rx, run_rx0, run_rx1;
+
+ rx_frontend #(.BASE(SR_RX_FRONT)) rx_frontend
+ (.clk(wb_clk),.rst(wb_rst),
+ .set_stb(set_stb),.set_addr(set_addr),.set_data(set_data),
+ .adc_a({rx_i,4'b00}),.adc_ovf_a(0),
+ .adc_b({rx_q,4'b00}),.adc_ovf_b(0),
+ .i_out(adc_i), .q_out(adc_q), .run(run_rx0 | run_rx1), .debug());
+
+ // /////////////////////////////////////////////////////////////////////////
+ // DSP RX 0
+
+ wire [31:0] sample_rx0;
+ wire strobe_rx0;
+ wire [35:0] vita_rx_data0;
+ wire vita_rx_src_rdy0, vita_rx_dst_rdy0;
- dsp_core_rx #(.BASE(SR_RX_DSP)) dsp_core_rx
+ dsp_core_rx #(.BASE(SR_RX_DSP0)) dsp_core_rx0
(.clk(wb_clk),.rst(wb_rst),
.set_stb(set_stb),.set_addr(set_addr),.set_data(set_data),
- .adc_a({rx_i,2'b0}),.adc_ovf_a(0),.adc_b({rx_q,2'b0}),.adc_ovf_b(0),
- .sample(sample_rx), .run(run_rx), .strobe(strobe_rx),
- .debug(debug_rx_dsp) );
+ .adc_i(adc_i),.adc_ovf_i(0),.adc_q(adc_q),.adc_ovf_q(0),
+ .sample(sample_rx0), .run(run_rx0), .strobe(strobe_rx0),
+ .debug() );
+
+ vita_rx_chain #(.BASE(SR_RX_CTRL0), .UNIT(0), .FIFOSIZE(9), .PROT_ENG_FLAGS(0)) vita_rx_chain0
+ (.clk(wb_clk),.reset(wb_rst),.clear(clear_rx),
+ .set_stb(set_stb),.set_addr(set_addr),.set_data(set_data),
+ .vita_time(vita_time), .overrun(rx_overrun_dsp0),
+ .sample(sample_rx0), .run(run_rx0), .strobe(strobe_rx0),
+ .rx_data_o(vita_rx_data0), .rx_dst_rdy_i(vita_rx_dst_rdy0), .rx_src_rdy_o(vita_rx_src_rdy0),
+ .debug() );
- vita_rx_chain #(.BASE(SR_RX_CTRL), .UNIT(0), .FIFOSIZE(9), .PROT_ENG_FLAGS(0)) vita_rx_chain
+ // /////////////////////////////////////////////////////////////////////////
+ // DSP RX 1
+
+ wire [31:0] sample_rx1;
+ wire strobe_rx1;
+ wire [35:0] vita_rx_data1;
+ wire vita_rx_src_rdy1, vita_rx_dst_rdy1;
+
+ dsp_core_rx #(.BASE(SR_RX_DSP1)) dsp_core_rx1
+ (.clk(wb_clk),.rst(wb_rst),
+ .set_stb(set_stb),.set_addr(set_addr),.set_data(set_data),
+ .adc_i(adc_i),.adc_ovf_i(0),.adc_q(adc_q),.adc_ovf_q(0),
+ .sample(sample_rx1), .run(run_rx1), .strobe(strobe_rx1),
+ .debug() );
+
+ vita_rx_chain #(.BASE(SR_RX_CTRL1), .UNIT(1), .FIFOSIZE(9), .PROT_ENG_FLAGS(0)) vita_rx_chain1
(.clk(wb_clk),.reset(wb_rst),.clear(clear_rx),
.set_stb(set_stb),.set_addr(set_addr),.set_data(set_data),
- .vita_time(vita_time), .overrun(rx_overrun_dsp),
- .sample(sample_rx), .run(run_rx), .strobe(strobe_rx),
- .rx_data_o(rx_data), .rx_dst_rdy_i(rx_dst_rdy), .rx_src_rdy_o(rx_src_rdy),
- .debug(vr_debug) );
+ .vita_time(vita_time), .overrun(rx_overrun_dsp1),
+ .sample(sample_rx1), .run(run_rx1), .strobe(strobe_rx1),
+ .rx_data_o(vita_rx_data1), .rx_dst_rdy_i(vita_rx_dst_rdy1), .rx_src_rdy_o(vita_rx_src_rdy1),
+ .debug() );
+
+ // /////////////////////////////////////////////////////////////////////////
+ // RX Stream muxing
+
+ fifo36_mux #(.prio(0)) mux_data_streams
+ (.clk(wb_clk), .reset(wb_rst), .clear(0),
+ .data0_i(vita_rx_data0), .src0_rdy_i(vita_rx_src_rdy0), .dst0_rdy_o(vita_rx_dst_rdy0),
+ .data1_i(vita_rx_data1), .src1_rdy_i(vita_rx_src_rdy1), .dst1_rdy_o(vita_rx_dst_rdy1),
+ .data_o(rx_data), .src_rdy_o(rx_src_rdy), .dst_rdy_i(rx_dst_rdy));
// ///////////////////////////////////////////////////////////////////////////////////
// DSP TX
- wire [15:0] tx_i_int, tx_q_int;
+ wire [23:0] tx_i_int, tx_q_int;
wire run_tx;
vita_tx_chain #(.BASE_CTRL(SR_TX_CTRL), .BASE_DSP(SR_TX_DSP),
@@ -170,13 +222,16 @@ module u1plus_core
.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(tx_i_int),.dac_b(tx_q_int),
+ .tx_i(tx_i_int),.tx_q(tx_q_int),
.underrun(tx_underrun_dsp), .run(run_tx),
.debug(debug_vt));
-
- assign tx_i = tx_i_int[15:2];
- assign tx_q = tx_q_int[15:2];
-
+
+ tx_frontend #(.BASE(SR_TX_FRONT), .WIDTH_OUT(14)) tx_frontend
+ (.clk(wb_clk), .rst(wb_rst),
+ .set_stb(set_stb),.set_addr(set_addr),.set_data(set_data),
+ .tx_i(tx_i_int), .tx_q(tx_q_int), .run(1'b1),
+ .dac_a(tx_i), .dac_b(tx_q));
+
// /////////////////////////////////////////////////////////////////////////////////////
// Wishbone Intercon, single master
wire [dw-1:0] s0_dat_mosi, s1_dat_mosi, s0_dat_miso, s1_dat_miso, s2_dat_mosi, s3_dat_mosi, s2_dat_miso, s3_dat_miso,
@@ -263,7 +318,7 @@ module u1plus_core
reg_leds <= 0;
reg_cgen_ctrl <= 2'b11;
reg_test <= 0;
- xfer_rate <= 0;
+ //xfer_rate <= 0;
frames_per_packet <= 0;
end
else
@@ -277,8 +332,8 @@ module u1plus_core
reg_test <= s0_dat_mosi;
REG_RX_FRAMELEN :
frames_per_packet <= s0_dat_mosi[7:0];
- REG_XFER_RATE :
- xfer_rate <= s0_dat_mosi;
+ //REG_XFER_RATE :
+ //xfer_rate <= s0_dat_mosi;
endcase // case (s0_adr[6:0])
assign test_ctrl = xfer_rate[11:8];
@@ -300,14 +355,16 @@ module u1plus_core
// /////////////////////////////////////////////////////////////////////////////////////
// Slave 1, UART
// depth of 3 is 128 entries, clkdiv of 278 gives 230.4k with a 64 MHz system clock
-
+
+/*
simple_uart #(.TXDEPTH(3),.RXDEPTH(3), .CLKDIV_DEFAULT(278)) uart
(.clk_i(wb_clk),.rst_i(wb_rst),
.we_i(s1_we),.stb_i(s1_stb),.cyc_i(s1_cyc),.ack_o(s1_ack),
.adr_i(s1_adr[3:1]),.dat_i({16'd0,s1_dat_mosi}),.dat_o(s1_dat_miso),
.rx_int_o(),.tx_int_o(),
.tx_o(debug_txd),.rx_i(debug_rxd),.baud_o());
-
+*/
+
// /////////////////////////////////////////////////////////////////////////////////////
// Slave 2, SPI
@@ -401,9 +458,8 @@ module u1plus_core
// Debug circuitry
assign debug_clk = { gpif_clk, clk_fpga };
- assign debug = debug0;
+ assign debug = 0;
assign debug_gpio_0 = 0;
assign debug_gpio_1 = 0;
- //assign {io_tx,io_rx} = {debug1};
endmodule // u1plus_core
diff --git a/fpga/usrp2/top/E1x0/Makefile.passthru b/fpga/usrp2/top/E1x0/Makefile.passthru
deleted file mode 100644
index f2d835608..000000000
--- a/fpga/usrp2/top/E1x0/Makefile.passthru
+++ /dev/null
@@ -1,98 +0,0 @@
-#
-# Copyright 2008 Ettus Research LLC
-#
-
-##################################################
-# Project Setup
-##################################################
-TOP_MODULE = passthru
-BUILD_DIR = $(abspath build$(ISE))
-
-##################################################
-# Include other makefiles
-##################################################
-
-include ../Makefile.common
-include ../../fifo/Makefile.srcs
-include ../../control_lib/Makefile.srcs
-include ../../sdr_lib/Makefile.srcs
-include ../../serdes/Makefile.srcs
-include ../../simple_gemac/Makefile.srcs
-include ../../timing/Makefile.srcs
-include ../../opencores/Makefile.srcs
-include ../../vrt/Makefile.srcs
-include ../../udp/Makefile.srcs
-include ../../coregen/Makefile.srcs
-include ../../gpmc/Makefile.srcs
-
-##################################################
-# Project Properties
-##################################################
-export PROJECT_PROPERTIES := \
-family "Spartan-3A DSP" \
-device xc3sd1800a \
-package cs484 \
-speed -4 \
-top_level_module_type "HDL" \
-synthesis_tool "XST (VHDL/Verilog)" \
-simulator "ISE Simulator (VHDL/Verilog)" \
-"Preferred Language" "Verilog" \
-"Enable Message Filtering" FALSE \
-"Display Incremental Messages" FALSE
-
-##################################################
-# Sources
-##################################################
-TOP_SRCS = \
-passthru.v \
-passthru.ucf
-
-SOURCES = $(abspath $(TOP_SRCS)) $(FIFO_SRCS) \
-$(CONTROL_LIB_SRCS) $(SDR_LIB_SRCS) $(SERDES_SRCS) \
-$(SIMPLE_GEMAC_SRCS) $(TIMING_SRCS) $(OPENCORES_SRCS) \
-$(VRT_SRCS) $(UDP_SRCS) $(COREGEN_SRCS) \
-$(GPMC_SRCS)
-
-##################################################
-# Process Properties
-##################################################
-SYNTHESIZE_PROPERTIES = \
-"Number of Clock Buffers" 8 \
-"Pack I/O Registers into IOBs" Yes \
-"Optimization Effort" High \
-"Optimize Instantiated Primitives" TRUE \
-"Register Balancing" Yes \
-"Use Clock Enable" Auto \
-"Use Synchronous Reset" Auto \
-"Use Synchronous Set" Auto
-
-TRANSLATE_PROPERTIES = \
-"Macro Search Path" "$(shell pwd)/../../coregen/"
-
-MAP_PROPERTIES = \
-"Allow Logic Optimization Across Hierarchy" TRUE \
-"Map to Input Functions" 4 \
-"Optimization Strategy (Cover Mode)" Speed \
-"Pack I/O Registers/Latches into IOBs" "For Inputs and Outputs" \
-"Perform Timing-Driven Packing and Placement" TRUE \
-"Map Effort Level" High \
-"Extra Effort" Normal \
-"Combinatorial Logic Optimization" TRUE \
-"Register Duplication" TRUE
-
-PLACE_ROUTE_PROPERTIES = \
-"Place & Route Effort Level (Overall)" High
-
-STATIC_TIMING_PROPERTIES = \
-"Number of Paths in Error/Verbose Report" 10 \
-"Report Type" "Error Report"
-
-GEN_PROG_FILE_PROPERTIES = \
-"Configuration Rate" 6 \
-"Create Binary Configuration File" TRUE \
-"Done (Output Events)" 5 \
-"Enable Bitstream Compression" TRUE \
-"Enable Outputs (Output Events)" 6 \
-"Unused IOB Pins" "Pull Up"
-
-SIM_MODEL_PROPERTIES = ""
diff --git a/fpga/usrp2/top/E1x0/core_compile b/fpga/usrp2/top/E1x0/core_compile
index dc0cd081e..02d7f006e 100755
--- a/fpga/usrp2/top/E1x0/core_compile
+++ b/fpga/usrp2/top/E1x0/core_compile
@@ -1,3 +1,3 @@
-iverilog -Wall -y. -y ../../control_lib/ -y ../../fifo/ -y ../../gpmc/ -y ../../models/ -y ../../sdr_lib/ -y ../../coregen/ -y ../../vrt/ -y ../../opencores/i2c/rtl/verilog/ -y ../../opencores/spi/rtl/verilog/ -y ../../timing/ -y ../../opencores/8b10b/ -I ../../opencores/spi/rtl/verilog/ -I ../../opencores/i2c/rtl/verilog/ -y ../../simple_gemac u1e_core.v 2>&1 | grep -v timescale | grep -v coregen | grep -v models
+iverilog -Wall -y. -y ../../control_lib/ -y ../../fifo/ -y ../../gpmc/ -y ../../models/ -y ../../sdr_lib/ -y ../../coregen/ -y ../../vrt/ -y ../../opencores/i2c/rtl/verilog/ -y ../../opencores/spi/rtl/verilog/ -y ../../timing/ -y ../../opencores/8b10b/ -I ../../opencores/spi/rtl/verilog/ -I ../../opencores/i2c/rtl/verilog/ -y ../../simple_gemac -y $XILINX/verilog/src/unisims u1e_core.v 2>&1 | grep -v timescale | grep -v coregen | grep -v models
diff --git a/fpga/usrp2/top/E1x0/passthru.ucf b/fpga/usrp2/top/E1x0/passthru.ucf
deleted file mode 100644
index 64e6f0440..000000000
--- a/fpga/usrp2/top/E1x0/passthru.ucf
+++ /dev/null
@@ -1,6 +0,0 @@
-NET "overo_gpio145" LOC = "C7" ;
-NET "cgen_mosi" LOC = "E22" ;
-NET "cgen_sclk" LOC = "J19" ;
-NET "cgen_sen_b" LOC = "H20" ;
-NET "fpga_cfg_din" LOC = "W17" ;
-NET "fpga_cfg_cclk" LOC = "V17" ;
diff --git a/fpga/usrp2/top/E1x0/u1e.v b/fpga/usrp2/top/E1x0/u1e.v
index adf42fd07..4f85b7d6e 100644
--- a/fpga/usrp2/top/E1x0/u1e.v
+++ b/fpga/usrp2/top/E1x0/u1e.v
@@ -36,11 +36,12 @@ module u1e
output cgen_sclk, output cgen_sen_b, output cgen_mosi, input cgen_miso, // Clock gen SPI
input cgen_st_status, input cgen_st_ld, input cgen_st_refmon, output cgen_sync_b, output cgen_ref_sel,
+ input overo_gpio65, input overo_gpio128, input overo_gpio145, output overo_gpio147, //aux SPI
- output overo_gpio144, output overo_gpio145, output overo_gpio146, output overo_gpio147, // Fifo controls
+ output overo_gpio144, output overo_gpio146, // Fifo controls
input overo_gpio0, input overo_gpio14, input overo_gpio21, input overo_gpio22, // Misc GPIO
- input overo_gpio23, input overo_gpio64, input overo_gpio65, input overo_gpio127, // Misc GPIO
- input overo_gpio128, input overo_gpio163, input overo_gpio170, input overo_gpio176, // Misc GPIO
+ input overo_gpio23, input overo_gpio64, input overo_gpio127, // Misc GPIO
+ input overo_gpio176, input overo_gpio163, input overo_gpio170, // Misc GPIO
inout [15:0] io_tx, inout [15:0] io_rx,
@@ -75,19 +76,29 @@ module u1e
clk_doubler (.CLKFB(clk_fb), .CLKIN(clk_fpga_in), .RST(dcm_rst),
.DSSEN(0), .PSCLK(0), .PSEN(0), .PSINCDEC(0), .PSDONE(),
.CLKDV(), .CLKFX(), .CLKFX180(),
- .CLK2X(), .CLK2X180(),
+ .CLK2X(clk_2x), .CLK2X180(),
.CLK0(clk_fb), .CLK90(clk_fpga), .CLK180(), .CLK270(),
.LOCKED(dcm_locked), .STATUS());
-
+
// /////////////////////////////////////////////////////////////////////////
// SPI
wire mosi, sclk, miso;
assign { db_sclk_tx, db_mosi_tx } = ~db_sen_tx ? {sclk,mosi} : 2'b0;
assign { db_sclk_rx, db_mosi_rx } = ~db_sen_rx ? {sclk,mosi} : 2'b0;
assign { sclk_codec, mosi_codec } = ~sen_codec ? {sclk,mosi} : 2'b0;
- assign { cgen_sclk, cgen_mosi } = ~cgen_sen_b ? {sclk,mosi} : 2'b0;
+ //assign { cgen_sclk, cgen_mosi } = ~cgen_sen_b ? {sclk,mosi} : 2'b0; //replaced by aux spi
assign miso = (~db_sen_tx & db_miso_tx) | (~db_sen_rx & db_miso_rx) |
- (~sen_codec & miso_codec) | (~cgen_sen_b & cgen_miso);
+ (~sen_codec & miso_codec) | (~cgen_sen_b & cgen_miso);
+
+ //assign the aux spi to the cgen (bypasses wishbone)
+ assign cgen_sclk = overo_gpio65;
+ assign cgen_sen_b = overo_gpio128;
+ assign cgen_mosi = overo_gpio145;
+ wire proc_int; //re-purpose gpio for interrupt when we are not using aux spi
+ assign overo_gpio147 = (cgen_sen_b == 1'b0)? cgen_miso : proc_int;
+
+ wire _cgen_sen_b;
+ //assign cgen_sen_b = _cgen_sen_b; //replaced by aux spi
// /////////////////////////////////////////////////////////////////////////
// TX DAC -- handle the interleaved data bus to DAC, with clock doubling DLL
@@ -130,25 +141,22 @@ module u1e
// /////////////////////////////////////////////////////////////////////////
// Main U1E Core
- u1e_core u1e_core(.clk_fpga(clk_fpga), .rst_fpga(~debug_pb),
+ u1e_core u1e_core(.clk_fpga(clk_fpga), .bus_clk(clk_2x), .rst_fpga(~debug_pb),
.debug_led(debug_led), .debug(debug), .debug_clk(debug_clk),
.debug_txd(FPGA_TXD), .debug_rxd(FPGA_RXD),
.EM_CLK(EM_CLK), .EM_D(EM_D), .EM_A(EM_A), .EM_NBE(EM_NBE),
.EM_WAIT0(EM_WAIT0), .EM_NCS4(EM_NCS4), .EM_NCS5(EM_NCS5),
.EM_NCS6(EM_NCS6), .EM_NWE(EM_NWE), .EM_NOE(EM_NOE),
.db_sda(db_sda), .db_scl(db_scl),
- .sclk(sclk), .sen({cgen_sen_b,sen_codec,db_sen_tx,db_sen_rx}), .mosi(mosi), .miso(miso),
+ .sclk(sclk), .sen({_cgen_sen_b,sen_codec,db_sen_tx,db_sen_rx}), .mosi(mosi), .miso(miso),
.cgen_st_status(cgen_st_status), .cgen_st_ld(cgen_st_ld),.cgen_st_refmon(cgen_st_refmon),
.cgen_sync_b(cgen_sync_b), .cgen_ref_sel(cgen_ref_sel),
- .tx_have_space(overo_gpio144), .tx_underrun(overo_gpio145),
- .rx_have_data(overo_gpio146), .rx_overrun(overo_gpio147),
+ .tx_have_space(overo_gpio144),
+ .rx_have_data(overo_gpio146),
.io_tx(io_tx), .io_rx(io_rx),
.tx_i(tx_i), .tx_q(tx_q),
.rx_i(DA), .rx_q(DB),
- .misc_gpio( {{overo_gpio128,overo_gpio163,overo_gpio170,overo_gpio176},
- {overo_gpio0,overo_gpio14,overo_gpio21,overo_gpio22},
- {overo_gpio23,overo_gpio64,overo_gpio65,overo_gpio127}}),
- .pps_in(PPS_IN) );
+ .pps_in(PPS_IN), .proc_int(proc_int) );
// /////////////////////////////////////////////////////////////////////////
// Local Debug
diff --git a/fpga/usrp2/top/E1x0/u1e_core.v b/fpga/usrp2/top/E1x0/u1e_core.v
index 4c513587b..d481867e3 100644
--- a/fpga/usrp2/top/E1x0/u1e_core.v
+++ b/fpga/usrp2/top/E1x0/u1e_core.v
@@ -18,7 +18,7 @@
module u1e_core
- (input clk_fpga, input rst_fpga,
+ (input clk_fpga, input bus_clk, input rst_fpga,
output [3:0] debug_led, output [31:0] debug, output [1:0] debug_clk,
output debug_txd, input debug_rxd,
@@ -31,29 +31,36 @@ module u1e_core
output sclk, output [15:0] sen, output mosi, input miso,
input cgen_st_status, input cgen_st_ld, input cgen_st_refmon, output cgen_sync_b, output cgen_ref_sel,
- output tx_have_space, output tx_underrun, output rx_have_data, output rx_overrun,
+ output tx_have_space, output rx_have_data,
inout [15:0] io_tx, inout [15:0] io_rx,
output [13:0] tx_i, output [13:0] tx_q,
input [11:0] rx_i, input [11:0] rx_q,
- input [11:0] misc_gpio, input pps_in
+ input pps_in, output proc_int
);
localparam TXFIFOSIZE = 13;
localparam RXFIFOSIZE = 13;
// 64 total regs in address space
- localparam SR_RX_CTRL = 0; // 9 regs (+0 to +8)
- localparam SR_RX_DSP = 16; // 7 regs (+0 to +6)
- localparam SR_TX_CTRL = 24; // 6 regs (+0 to +5)
- localparam SR_TX_DSP = 32; // 5 regs (+0 to +4)
- localparam SR_TIME64 = 40; // 6 regs (+0 to +5)
- localparam SR_CLEAR_RX_FIFO = 48; // 1 reg
- localparam SR_CLEAR_TX_FIFO = 49; // 1 reg
- localparam SR_GLOBAL_RESET = 50; // 1 reg
- localparam SR_REG_TEST32 = 52; // 1 reg
-
- wire [7:0] COMPAT_NUM = 8'd4;
+ localparam SR_RX_CTRL0 = 0; // 9 regs (+0 to +8)
+ localparam SR_RX_DSP0 = 10; // 4 regs (+0 to +3)
+ localparam SR_RX_CTRL1 = 16; // 9 regs (+0 to +8)
+ localparam SR_RX_DSP1 = 26; // 4 regs (+0 to +3)
+ localparam SR_ERR_CTRL = 30; // 1 reg
+ localparam SR_TX_CTRL = 32; // 4 regs (+0 to +3)
+ localparam SR_TX_DSP = 38; // 3 regs (+0 to +2)
+
+ localparam SR_TIME64 = 42; // 6 regs (+0 to +5)
+ localparam SR_RX_FRONT = 48; // 5 regs (+0 to +4)
+ localparam SR_TX_FRONT = 54; // 5 regs (+0 to +4)
+
+ localparam SR_REG_TEST32 = 60; // 1 reg
+ localparam SR_CLEAR_RX_FIFO = 61; // 1 reg
+ localparam SR_CLEAR_TX_FIFO = 62; // 1 reg
+ localparam SR_GLOBAL_RESET = 63; // 1 reg
+
+ wire [7:0] COMPAT_NUM = 8'd5;
wire wb_clk = clk_fpga;
wire wb_rst, global_reset;
@@ -69,9 +76,9 @@ module u1e_core
wire set_stb;
wire [31:0] debug_vt;
- wire rx_overrun_dsp, rx_overrun_gpmc, tx_underrun_dsp, tx_underrun_gpmc;
- assign rx_overrun = rx_overrun_gpmc | rx_overrun_dsp;
- assign tx_underrun = tx_underrun_gpmc | tx_underrun_dsp;
+ wire rx_overrun_dsp0, rx_overrun_dsp1, rx_overrun_gpmc, tx_underrun_dsp, tx_underrun_gpmc;
+ wire rx_overrun = rx_overrun_gpmc | rx_overrun_dsp0 | rx_overrun_dsp1;
+ wire tx_underrun = tx_underrun_gpmc | tx_underrun_dsp;
setting_reg #(.my_addr(SR_GLOBAL_RESET), .width(1)) sr_reset
(.clk(wb_clk),.rst(wb_rst),.strobe(set_stb),.addr(set_addr),
@@ -110,7 +117,7 @@ module u1e_core
.in(set_data),.out(),.changed(clear_tx));
gpmc_async #(.TXFIFOSIZE(TXFIFOSIZE), .RXFIFOSIZE(RXFIFOSIZE))
- gpmc (.arst(wb_rst),
+ gpmc (.arst(wb_rst), .bus_clk(bus_clk),
.EM_CLK(EM_CLK), .EM_D(EM_D), .EM_A(EM_A), .EM_NBE(EM_NBE),
.EM_WAIT0(EM_WAIT0), .EM_NCS4(EM_NCS4), .EM_NCS6(EM_NCS6), .EM_NWE(EM_NWE),
.EM_NOE(EM_NOE),
@@ -133,44 +140,82 @@ module u1e_core
.test_rate(test_rate), .test_ctrl(test_ctrl),
.debug(debug_gpmc));
- wire rx_sof = rx_data[32];
- wire rx_eof = rx_data[33];
wire rx_src_rdy_int, rx_dst_rdy_int, tx_src_rdy_int, tx_dst_rdy_int;
wire [31:0] debug_rx_dsp, vrc_debug, vrf_debug, vr_debug;
// /////////////////////////////////////////////////////////////////////////
- // DSP RX
- wire [31:0] sample_rx;
- wire strobe_rx, run_rx;
- wire [35:0] vita_rx_data;
- wire vita_rx_src_rdy, vita_rx_dst_rdy;
+ // RX ADC Frontend, does IQ Balance, DC Offset, muxing
+
+ wire [23:0] adc_i, adc_q; // 24 bits is total overkill here, but it matches u2/u2p
+ wire run_rx, run_rx0, run_rx1;
- dsp_core_rx #(.BASE(SR_RX_DSP)) dsp_core_rx
+ rx_frontend #(.BASE(SR_RX_FRONT)) rx_frontend
(.clk(wb_clk),.rst(wb_rst),
.set_stb(set_stb),.set_addr(set_addr),.set_data(set_data),
- .adc_a({rx_i,2'b0}),.adc_ovf_a(0),.adc_b({rx_q,2'b0}),.adc_ovf_b(0),
- .sample(sample_rx), .run(run_rx), .strobe(strobe_rx),
- .debug(debug_rx_dsp) );
+ .adc_a({rx_i,4'b00}),.adc_ovf_a(0),
+ .adc_b({rx_q,4'b00}),.adc_ovf_b(0),
+ .i_out(adc_i), .q_out(adc_q), .run(run_rx0 | run_rx1), .debug());
+
+ // /////////////////////////////////////////////////////////////////////////
+ // DSP RX 0
- vita_rx_chain #(.BASE(SR_RX_CTRL), .UNIT(0), .FIFOSIZE(9), .PROT_ENG_FLAGS(0)) vita_rx_chain
+ wire [31:0] sample_rx0;
+ wire strobe_rx0;
+ wire [35:0] vita_rx_data0;
+ wire vita_rx_src_rdy0, vita_rx_dst_rdy0;
+
+ dsp_core_rx #(.BASE(SR_RX_DSP0)) dsp_core_rx0
+ (.clk(wb_clk),.rst(wb_rst),
+ .set_stb(set_stb),.set_addr(set_addr),.set_data(set_data),
+ .adc_i(adc_i),.adc_ovf_i(0),.adc_q(adc_q),.adc_ovf_q(0),
+ .sample(sample_rx0), .run(run_rx0), .strobe(strobe_rx0),
+ .debug() );
+
+ vita_rx_chain #(.BASE(SR_RX_CTRL0), .UNIT(0), .FIFOSIZE(9), .PROT_ENG_FLAGS(0)) vita_rx_chain0
(.clk(wb_clk),.reset(wb_rst),.clear(clear_rx),
.set_stb(set_stb),.set_addr(set_addr),.set_data(set_data),
- .vita_time(vita_time), .overrun(rx_overrun_dsp),
- .sample(sample_rx), .run(run_rx), .strobe(strobe_rx),
- .rx_data_o(vita_rx_data), .rx_dst_rdy_i(vita_rx_dst_rdy), .rx_src_rdy_o(vita_rx_src_rdy),
- .debug(vr_debug) );
+ .vita_time(vita_time), .overrun(rx_overrun_dsp0),
+ .sample(sample_rx0), .run(run_rx0), .strobe(strobe_rx0),
+ .rx_data_o(vita_rx_data0), .rx_dst_rdy_i(vita_rx_dst_rdy0), .rx_src_rdy_o(vita_rx_src_rdy0),
+ .debug() );
- fifo36_mux #(.prio(0)) mux_err_stream
+ // /////////////////////////////////////////////////////////////////////////
+ // DSP RX 1
+
+ wire [31:0] sample_rx1;
+ wire strobe_rx1;
+ wire [35:0] vita_rx_data1;
+ wire vita_rx_src_rdy1, vita_rx_dst_rdy1;
+
+ dsp_core_rx #(.BASE(SR_RX_DSP1)) dsp_core_rx1
+ (.clk(wb_clk),.rst(wb_rst),
+ .set_stb(set_stb),.set_addr(set_addr),.set_data(set_data),
+ .adc_i(adc_i),.adc_ovf_i(0),.adc_q(adc_q),.adc_ovf_q(0),
+ .sample(sample_rx1), .run(run_rx1), .strobe(strobe_rx1),
+ .debug() );
+
+ vita_rx_chain #(.BASE(SR_RX_CTRL1), .UNIT(1), .FIFOSIZE(9), .PROT_ENG_FLAGS(0)) vita_rx_chain1
+ (.clk(wb_clk),.reset(wb_rst),.clear(clear_rx),
+ .set_stb(set_stb),.set_addr(set_addr),.set_data(set_data),
+ .vita_time(vita_time), .overrun(rx_overrun_dsp1),
+ .sample(sample_rx1), .run(run_rx1), .strobe(strobe_rx1),
+ .rx_data_o(vita_rx_data1), .rx_dst_rdy_i(vita_rx_dst_rdy1), .rx_src_rdy_o(vita_rx_src_rdy1),
+ .debug() );
+
+ // /////////////////////////////////////////////////////////////////////////
+ // RX Stream muxing
+
+ fifo36_mux #(.prio(0)) mux_data_streams
(.clk(wb_clk), .reset(wb_rst), .clear(0),
- .data0_i(vita_rx_data), .src0_rdy_i(vita_rx_src_rdy), .dst0_rdy_o(vita_rx_dst_rdy),
- .data1_i(tx_err_data), .src1_rdy_i(tx_err_src_rdy), .dst1_rdy_o(tx_err_dst_rdy),
+ .data0_i(vita_rx_data0), .src0_rdy_i(vita_rx_src_rdy0), .dst0_rdy_o(vita_rx_dst_rdy0),
+ .data1_i(vita_rx_data1), .src1_rdy_i(vita_rx_src_rdy1), .dst1_rdy_o(vita_rx_dst_rdy1),
.data_o(rx_data), .src_rdy_o(rx_src_rdy), .dst_rdy_i(rx_dst_rdy));
-
+
// ///////////////////////////////////////////////////////////////////////////////////
// DSP TX
- wire [15:0] tx_i_int, tx_q_int;
+ wire [23:0] tx_i_int, tx_q_int;
wire run_tx;
vita_tx_chain #(.BASE_CTRL(SR_TX_CTRL), .BASE_DSP(SR_TX_DSP),
@@ -183,13 +228,16 @@ module u1e_core
.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(tx_i_int),.dac_b(tx_q_int),
+ .tx_i(tx_i_int),.tx_q(tx_q_int),
.underrun(tx_underrun_dsp), .run(run_tx),
.debug(debug_vt));
-
- assign tx_i = tx_i_int[15:2];
- assign tx_q = tx_q_int[15:2];
-
+
+ tx_frontend #(.BASE(SR_TX_FRONT), .WIDTH_OUT(14)) tx_frontend
+ (.clk(wb_clk), .rst(wb_rst),
+ .set_stb(set_stb),.set_addr(set_addr),.set_data(set_data),
+ .tx_i(tx_i_int), .tx_q(tx_q_int), .run(1'b1),
+ .dac_a(tx_i), .dac_b(tx_q));
+
// /////////////////////////////////////////////////////////////////////////////////////
// Wishbone Intercon, single master
wire [dw-1:0] s0_dat_mosi, s1_dat_mosi, s0_dat_miso, s1_dat_miso, s2_dat_mosi, s3_dat_mosi, s2_dat_miso, s3_dat_miso,
@@ -255,7 +303,7 @@ module u1e_core
.sf_dat_o(sf_dat_mosi),.sf_adr_o(sf_adr),.sf_sel_o(sf_sel),.sf_we_o(sf_we),.sf_cyc_o(sf_cyc),.sf_stb_o(sf_stb),
.sf_dat_i(sf_dat_miso),.sf_ack_i(sf_ack),.sf_err_i(0),.sf_rty_i(0) );
- assign s5_ack = 0; assign s9_ack = 0; assign sa_ack = 0; assign sb_ack = 0;
+ assign s9_ack = 0; assign sa_ack = 0; assign sb_ack = 0;
assign sc_ack = 0; assign sd_ack = 0; assign se_ack = 0; assign sf_ack = 0;
// /////////////////////////////////////////////////////////////////////////////////////
@@ -336,7 +384,7 @@ module u1e_core
wire scl_pad_i, scl_pad_o, scl_pad_oen_o, sda_pad_i, sda_pad_o, sda_pad_oen_o;
i2c_master_top #(.ARST_LVL(1)) i2c
(.wb_clk_i(wb_clk),.wb_rst_i(wb_rst),.arst_i(1'b0),
- .wb_adr_i(s3_adr[4:2]),.wb_dat_i(s3_dat_mosi[7:0]),.wb_dat_o(s3_dat_miso[7:0]),
+ .wb_adr_i(s3_adr[3:1]),.wb_dat_i(s3_dat_mosi[7:0]),.wb_dat_o(s3_dat_miso[7:0]),
.wb_we_i(s3_we),.wb_stb_i(s3_stb),.wb_cyc_i(s3_cyc),
.wb_ack_o(s3_ack),.wb_inta_o(),
.scl_pad_i(scl_pad_i),.scl_pad_o(scl_pad_o),.scl_padoen_o(scl_pad_oen_o),
@@ -361,6 +409,43 @@ module u1e_core
.atr(atr_lines),.debug_0(debug_gpio_0),.debug_1(debug_gpio_1),
.gpio( {io_tx,io_rx} ) );
+ ////////////////////////////////////////////////////////////////////////////
+ // FIFO to WB slave for async messages - Slave #5
+
+ //signals between fifo and buffer module
+ wire [35:0] _tx_err_data;
+ wire _tx_err_src_rdy, _tx_err_dst_rdy;
+
+ fifo_cascade #(.WIDTH(36), .SIZE(9/*512 lines plenty for short pkts*/)) err_fifo(
+ .clk(wb_clk), .reset(wb_rst), .clear(wb_rst),
+ .datain(tx_err_data), .src_rdy_i(tx_err_src_rdy), .dst_rdy_o(tx_err_dst_rdy),
+ .dataout(_tx_err_data), .src_rdy_o(_tx_err_src_rdy), .dst_rdy_i(_tx_err_dst_rdy)
+ );
+
+ wire [31:0] err_status, err_data32;
+ //the buffer is 32 bits, but the data is 16, so mux based on the addr bit
+ assign s5_dat_miso = (s5_adr[1] == 1'b0)? err_data32[15:0] : err_data32[31:16];
+
+ buffer_int2 #(.BASE(SR_ERR_CTRL), .BUF_SIZE(5)) fifo_to_wb(
+ .clk(wb_clk), .rst(wb_rst),
+ .set_stb(set_stb), .set_addr(set_addr), .set_data(set_data),
+ .status(err_status),
+ // Wishbone interface to RAM
+ .wb_clk_i(wb_clk), .wb_rst_i(wb_rst),
+ .wb_we_i(s5_we), .wb_stb_i(s5_stb),
+ .wb_adr_i(s5_adr), .wb_dat_i({16'b0, s5_dat_mosi}),
+ .wb_dat_o(err_data32), .wb_ack_o(s5_ack),
+ // Write FIFO Interface
+ .wr_data_i(_tx_err_data), .wr_ready_i(_tx_err_src_rdy), .wr_ready_o(_tx_err_dst_rdy),
+ // Read FIFO Interface
+ .rd_data_o(), .rd_ready_o(), .rd_ready_i(1'b0)
+ );
+
+ ////////////////////////////////////////////////////////////////////////////
+ // Interrupts
+
+ assign proc_int = (|err_status[1:0]);
+
// /////////////////////////////////////////////////////////////////////////
// Settings Bus -- Slave #8 + 9
@@ -369,7 +454,7 @@ module u1e_core
(.wb_clk(wb_clk),.wb_rst(wb_rst),.wb_adr_i(s8_adr),.wb_dat_i(s8_dat_mosi),
.wb_stb_i(s8_stb),.wb_we_i(s8_we),.wb_ack_o(s8_ack),
.strobe(set_stb),.addr(set_addr),.data(set_data) );
-
+
// /////////////////////////////////////////////////////////////////////////
// ATR Controller -- Slave #6
@@ -384,8 +469,9 @@ module u1e_core
wire [31:0] reg_test32;
+ //this setting reg is persistent across resets, to check for fpga loaded
setting_reg #(.my_addr(SR_REG_TEST32)) sr_reg_test32
- (.clk(wb_clk),.rst(wb_rst),.strobe(set_stb),.addr(set_addr),
+ (.clk(wb_clk),.rst(/*wb_rst*/1'b0),.strobe(set_stb),.addr(set_addr),
.in(set_data),.out(reg_test32),.changed());
wb_readback_mux_16LE readback_mux_32
@@ -394,7 +480,7 @@ module u1e_core
.word00(vita_time[63:32]), .word01(vita_time[31:0]),
.word02(vita_time_pps[63:32]), .word03(vita_time_pps[31:0]),
- .word04(reg_test32), .word05(32'b0),
+ .word04(reg_test32), .word05(err_status),
.word06(32'b0), .word07(32'b0),
.word08(32'b0), .word09(32'b0),
.word10(32'b0), .word11(32'b0),
@@ -423,7 +509,7 @@ module u1e_core
*/
assign debug = debug_gpmc;
- assign debug_gpio_0 = { {run_tx, 1'b0, run_rx, strobe_rx, tx_i[11:0]},
+ assign debug_gpio_0 = { {run_tx, 1'b0, run_rx, strobe_rx0, tx_i[11:0]},
{2'b00, tx_src_rdy, tx_dst_rdy, tx_q[11:0]} };
assign debug_gpio_1 = debug_vt;
@@ -431,7 +517,7 @@ module u1e_core
/*
assign debug_gpio_1 = { {rx_enable, rx_src_rdy, rx_dst_rdy, rx_src_rdy & ~rx_dst_rdy},
{tx_enable, tx_src_rdy, tx_dst_rdy, tx_dst_rdy & ~tx_src_rdy},
- {rx_sof, rx_eof, rx_src_rdy, rx_dst_rdy, rx_data[33:32],2'b0},
+ {2'b0, rx_src_rdy, rx_dst_rdy, rx_data[33:32],2'b0},
{2'b0, bus_error, debug_gpmc[4:0] },
{misc_gpio[7:0]} };
*/
diff --git a/fpga/usrp2/top/N2x0/u2plus_core.v b/fpga/usrp2/top/N2x0/u2plus_core.v
index 8a7c6ddee..e2142ad06 100644
--- a/fpga/usrp2/top/N2x0/u2plus_core.v
+++ b/fpga/usrp2/top/N2x0/u2plus_core.v
@@ -428,7 +428,7 @@ module u2plus_core
// Buffer Pool Status -- Slave #5
//compatibility number -> increment when the fpga has been sufficiently altered
- localparam compat_num = 32'd6;
+ localparam compat_num = {16'd7, 16'd0}; //major, minor
wb_readback_mux buff_pool_status
(.wb_clk_i(wb_clk), .wb_rst_i(wb_rst), .wb_stb_i(s5_stb),
@@ -584,6 +584,17 @@ module u2plus_core
.sclk_pad_o(spiflash_clk),.mosi_pad_o(spiflash_mosi),.miso_pad_i(spiflash_miso) );
// /////////////////////////////////////////////////////////////////////////
+ // ADC Frontend
+ wire [23:0] adc_i, adc_q;
+
+ rx_frontend #(.BASE(SR_RX_FRONT)) rx_frontend
+ (.clk(dsp_clk),.rst(dsp_rst),
+ .set_stb(set_stb_dsp),.set_addr(set_addr_dsp),.set_data(set_data_dsp),
+ .adc_a({adc_a,2'b00}),.adc_ovf_a(adc_ovf_a),
+ .adc_b({adc_b,2'b00}),.adc_ovf_b(adc_ovf_b),
+ .i_out(adc_i), .q_out(adc_q), .run(run_rx0_d1 | run_rx1_d1), .debug());
+
+ // /////////////////////////////////////////////////////////////////////////
// DSP RX 0
wire [31:0] sample_rx0;
wire clear_rx0, strobe_rx0;
@@ -594,7 +605,7 @@ module u2plus_core
dsp_core_rx #(.BASE(SR_RX_DSP0)) dsp_core_rx0
(.clk(dsp_clk),.rst(dsp_rst),
.set_stb(set_stb_dsp),.set_addr(set_addr_dsp),.set_data(set_data_dsp),
- .adc_a(adc_a),.adc_ovf_a(adc_ovf_a),.adc_b(adc_b),.adc_ovf_b(adc_ovf_b),
+ .adc_i(adc_i),.adc_ovf_i(adc_ovf_a),.adc_q(adc_q),.adc_ovf_q(adc_ovf_b),
.sample(sample_rx0), .run(run_rx0_d1), .strobe(strobe_rx0),
.debug() );
@@ -622,7 +633,7 @@ module u2plus_core
dsp_core_rx #(.BASE(SR_RX_DSP1)) dsp_core_rx1
(.clk(dsp_clk),.rst(dsp_rst),
.set_stb(set_stb_dsp),.set_addr(set_addr_dsp),.set_data(set_data_dsp),
- .adc_a(adc_a),.adc_ovf_a(adc_ovf_a),.adc_b(adc_b),.adc_ovf_b(adc_ovf_b),
+ .adc_i(adc_i),.adc_ovf_i(adc_ovf_a),.adc_q(adc_q),.adc_ovf_q(adc_ovf_b),
.sample(sample_rx1), .run(run_rx1_d1), .strobe(strobe_rx1),
.debug() );
@@ -676,6 +687,8 @@ module u2plus_core
.debug(debug_extfifo),
.debug2(debug_extfifo2) );
+ wire [23:0] tx_i, tx_q;
+
vita_tx_chain #(.BASE_CTRL(SR_TX_CTRL), .BASE_DSP(SR_TX_DSP),
.REPORT_ERROR(1), .DO_FLOW_CONTROL(1),
.PROT_ENG_FLAGS(1), .USE_TRANS_HEADER(1),
@@ -686,10 +699,16 @@ module u2plus_core
.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),
+ .tx_i(tx_i),.tx_q(tx_q),
.underrun(underrun), .run(run_tx),
.debug(debug_vt));
-
+
+ tx_frontend #(.BASE(SR_TX_FRONT)) tx_frontend
+ (.clk(dsp_clk), .rst(dsp_rst),
+ .set_stb(set_stb_dsp),.set_addr(set_addr_dsp),.set_data(set_data_dsp),
+ .tx_i(tx_i), .tx_q(tx_q), .run(1'b1),
+ .dac_a(dac_a), .dac_b(dac_b));
+
// ///////////////////////////////////////////////////////////////////////////////////
// SERDES
diff --git a/fpga/usrp2/top/USRP2/u2_core.v b/fpga/usrp2/top/USRP2/u2_core.v
index ca9762ac5..2e3d41731 100644
--- a/fpga/usrp2/top/USRP2/u2_core.v
+++ b/fpga/usrp2/top/USRP2/u2_core.v
@@ -283,7 +283,7 @@ module u2_core
.sf_dat_o(sf_dat_o),.sf_adr_o(sf_adr),.sf_sel_o(sf_sel),.sf_we_o(sf_we),.sf_cyc_o(sf_cyc),.sf_stb_o(sf_stb),
.sf_dat_i(sf_dat_i),.sf_ack_i(sf_ack),.sf_err_i(0),.sf_rty_i(0));
- //////////////////////////////////////////////////////////////////////////////////////////
+ // ////////////////////////////////////////////////////////////////////////////////////////
// Reset Controller
system_control sysctrl (.wb_clk_i(wb_clk), // .por_i(por),
.ram_loader_rst_o(ram_loader_rst),
@@ -433,7 +433,7 @@ module u2_core
// Buffer Pool Status -- Slave #5
//compatibility number -> increment when the fpga has been sufficiently altered
- localparam compat_num = 32'd6;
+ localparam compat_num = {16'd7, 16'd0}; //major, minor
wb_readback_mux buff_pool_status
(.wb_clk_i(wb_clk), .wb_rst_i(wb_rst), .wb_stb_i(s5_stb),
@@ -583,6 +583,17 @@ module u2_core
assign sd_dat_i[31:8] = 0;
// /////////////////////////////////////////////////////////////////////////
+ // ADC Frontend
+ wire [23:0] adc_i, adc_q;
+
+ rx_frontend #(.BASE(SR_RX_FRONT)) rx_frontend
+ (.clk(dsp_clk),.rst(dsp_rst),
+ .set_stb(set_stb_dsp),.set_addr(set_addr_dsp),.set_data(set_data_dsp),
+ .adc_a({adc_a,2'b00}),.adc_ovf_a(adc_ovf_a),
+ .adc_b({adc_b,2'b00}),.adc_ovf_b(adc_ovf_b),
+ .i_out(adc_i), .q_out(adc_q), .run(run_rx0_d1 | run_rx1_d1), .debug());
+
+ // /////////////////////////////////////////////////////////////////////////
// DSP RX 0
wire [31:0] sample_rx0;
wire clear_rx0, strobe_rx0;
@@ -593,7 +604,7 @@ module u2_core
dsp_core_rx #(.BASE(SR_RX_DSP0)) dsp_core_rx0
(.clk(dsp_clk),.rst(dsp_rst),
.set_stb(set_stb_dsp),.set_addr(set_addr_dsp),.set_data(set_data_dsp),
- .adc_a(adc_a),.adc_ovf_a(adc_ovf_a),.adc_b(adc_b),.adc_ovf_b(adc_ovf_b),
+ .adc_i(adc_i),.adc_ovf_i(adc_ovf_a),.adc_q(adc_q),.adc_ovf_q(adc_ovf_b),
.sample(sample_rx0), .run(run_rx0_d1), .strobe(strobe_rx0),
.debug() );
@@ -621,7 +632,7 @@ module u2_core
dsp_core_rx #(.BASE(SR_RX_DSP1)) dsp_core_rx1
(.clk(dsp_clk),.rst(dsp_rst),
.set_stb(set_stb_dsp),.set_addr(set_addr_dsp),.set_data(set_data_dsp),
- .adc_a(adc_a),.adc_ovf_a(adc_ovf_a),.adc_b(adc_b),.adc_ovf_b(adc_ovf_b),
+ .adc_i(adc_i),.adc_ovf_i(adc_ovf_a),.adc_q(adc_q),.adc_ovf_q(adc_ovf_b),
.sample(sample_rx1), .run(run_rx1_d1), .strobe(strobe_rx1),
.debug() );
@@ -673,6 +684,8 @@ module u2_core
.debug(debug_extfifo),
.debug2(debug_extfifo2) );
+ wire [23:0] tx_i, tx_q;
+
vita_tx_chain #(.BASE_CTRL(SR_TX_CTRL), .BASE_DSP(SR_TX_DSP),
.REPORT_ERROR(1), .DO_FLOW_CONTROL(1),
.PROT_ENG_FLAGS(1), .USE_TRANS_HEADER(1),
@@ -683,10 +696,16 @@ module u2_core
.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),
+ .tx_i(tx_i),.tx_q(tx_q),
.underrun(underrun), .run(run_tx),
.debug(debug_vt));
-
+
+ tx_frontend #(.BASE(SR_TX_FRONT)) tx_frontend
+ (.clk(dsp_clk), .rst(dsp_rst),
+ .set_stb(set_stb_dsp),.set_addr(set_addr_dsp),.set_data(set_data_dsp),
+ .tx_i(tx_i), .tx_q(tx_q), .run(1'b1),
+ .dac_a(dac_a), .dac_b(dac_b));
+
// ///////////////////////////////////////////////////////////////////////////////////
// SERDES
diff --git a/fpga/usrp2/vrt/vita_tx_chain.v b/fpga/usrp2/vrt/vita_tx_chain.v
index 542968afa..ac9f08fc8 100644
--- a/fpga/usrp2/vrt/vita_tx_chain.v
+++ b/fpga/usrp2/vrt/vita_tx_chain.v
@@ -29,7 +29,7 @@ module vita_tx_chain
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 [23:0] tx_i, output [23:0] tx_q,
output underrun, output run,
output [31:0] debug);
@@ -84,7 +84,7 @@ module vita_tx_chain
(.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),
+ .tx_i(tx_i),.tx_q(tx_q),
.debug(debug_tx_dsp) );
wire [35:0] flow_data, err_data_int;
diff --git a/host/CMakeLists.txt b/host/CMakeLists.txt
index b5f8e57c2..12c1cc179 100644
--- a/host/CMakeLists.txt
+++ b/host/CMakeLists.txt
@@ -26,7 +26,7 @@
CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
PROJECT(UHD CXX)
ENABLE_TESTING()
-LIST(APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/Modules)
+LIST(APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/Modules)
INCLUDE(UHDComponent) #enable components
INCLUDE(UHDPackage) #setup cpack
@@ -81,7 +81,7 @@ IF(CMAKE_COMPILER_IS_GNUCXX)
ENDIF(CMAKE_COMPILER_IS_GNUCXX)
IF(MSVC)
- INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/msvc)
+ INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/cmake/msvc)
ADD_DEFINITIONS( #stop all kinds of compatibility warnings
-D_SCL_SECURE_NO_WARNINGS
-D_SCL_SECURE_NO_DEPRECATE
@@ -160,7 +160,7 @@ PYTHON_CHECK_MODULE(
# Create Uninstall Target
########################################################################
CONFIGURE_FILE(
- ${CMAKE_CURRENT_SOURCE_DIR}/cmake_uninstall.cmake.in
+ ${CMAKE_SOURCE_DIR}/cmake/cmake_uninstall.cmake.in
${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake
@ONLY)
diff --git a/host/apps/omap_debug/usrp_e.h b/host/apps/omap_debug/usrp_e.h
index 4c6a5dd89..2c4aa2ac1 100644
--- a/host/apps/omap_debug/usrp_e.h
+++ b/host/apps/omap_debug/usrp_e.h
@@ -28,46 +28,15 @@ struct usrp_e_ctl32 {
__u32 buf[10];
};
-/* SPI interface */
-
-#define UE_SPI_TXONLY 0
-#define UE_SPI_TXRX 1
-
-/* Defines for spi ctrl register */
-#define UE_SPI_CTRL_TXNEG (1<<10)
-#define UE_SPI_CTRL_RXNEG (1<<9)
-
-#define UE_SPI_PUSH_RISE 0
-#define UE_SPI_PUSH_FALL UE_SPI_CTRL_TXNEG
-#define UE_SPI_LATCH_RISE 0
-#define UE_SPI_LATCH_FALL UE_SPI_CTRL_RXNEG
-
-struct usrp_e_spi {
- __u8 readback;
- __u32 slave;
- __u32 data;
- __u32 length;
- __u32 flags;
-};
-
-struct usrp_e_i2c {
- __u8 addr;
- __u32 len;
- __u8 data[];
-};
-
#define USRP_E_IOC_MAGIC 'u'
#define USRP_E_WRITE_CTL16 _IOW(USRP_E_IOC_MAGIC, 0x20, struct usrp_e_ctl16)
#define USRP_E_READ_CTL16 _IOWR(USRP_E_IOC_MAGIC, 0x21, struct usrp_e_ctl16)
#define USRP_E_WRITE_CTL32 _IOW(USRP_E_IOC_MAGIC, 0x22, struct usrp_e_ctl32)
#define USRP_E_READ_CTL32 _IOWR(USRP_E_IOC_MAGIC, 0x23, struct usrp_e_ctl32)
-#define USRP_E_SPI _IOWR(USRP_E_IOC_MAGIC, 0x24, struct usrp_e_spi)
-#define USRP_E_I2C_READ _IOWR(USRP_E_IOC_MAGIC, 0x25, struct usrp_e_i2c)
-#define USRP_E_I2C_WRITE _IOW(USRP_E_IOC_MAGIC, 0x26, struct usrp_e_i2c)
#define USRP_E_GET_RB_INFO _IOR(USRP_E_IOC_MAGIC, 0x27, struct usrp_e_ring_buffer_size_t)
#define USRP_E_GET_COMPAT_NUMBER _IO(USRP_E_IOC_MAGIC, 0x28)
-#define USRP_E_COMPAT_NUMBER 1
+#define USRP_E_COMPAT_NUMBER 2
/* Flag defines */
#define RB_USER (1<<0)
diff --git a/host/Modules/FindDocutils.cmake b/host/cmake/Modules/FindDocutils.cmake
index 3a97d8643..3a97d8643 100644
--- a/host/Modules/FindDocutils.cmake
+++ b/host/cmake/Modules/FindDocutils.cmake
diff --git a/host/Modules/FindGit.cmake b/host/cmake/Modules/FindGit.cmake
index 2d8214287..2d8214287 100644
--- a/host/Modules/FindGit.cmake
+++ b/host/cmake/Modules/FindGit.cmake
diff --git a/host/Modules/FindUSB1.cmake b/host/cmake/Modules/FindUSB1.cmake
index efb2e288b..efb2e288b 100644
--- a/host/Modules/FindUSB1.cmake
+++ b/host/cmake/Modules/FindUSB1.cmake
diff --git a/host/Modules/UHDComponent.cmake b/host/cmake/Modules/UHDComponent.cmake
index 52b7450d5..52b7450d5 100644
--- a/host/Modules/UHDComponent.cmake
+++ b/host/cmake/Modules/UHDComponent.cmake
diff --git a/host/Modules/UHDPackage.cmake b/host/cmake/Modules/UHDPackage.cmake
index e36793d73..e36793d73 100644
--- a/host/Modules/UHDPackage.cmake
+++ b/host/cmake/Modules/UHDPackage.cmake
diff --git a/host/Modules/UHDPython.cmake b/host/cmake/Modules/UHDPython.cmake
index fdcdccb4b..fdcdccb4b 100644
--- a/host/Modules/UHDPython.cmake
+++ b/host/cmake/Modules/UHDPython.cmake
diff --git a/host/Modules/UHDVersion.cmake b/host/cmake/Modules/UHDVersion.cmake
index f5364941c..ba736d2fc 100644
--- a/host/Modules/UHDVersion.cmake
+++ b/host/cmake/Modules/UHDVersion.cmake
@@ -26,8 +26,8 @@ FIND_PACKAGE(Git QUIET)
# - increment patch on for bug fixes and docs
########################################################################
SET(UHD_VERSION_MAJOR 003)
-SET(UHD_VERSION_MINOR 001)
-SET(UHD_VERSION_PATCH 002)
+SET(UHD_VERSION_MINOR 002)
+SET(UHD_VERSION_PATCH 000)
########################################################################
# Version information discovery through git log
diff --git a/host/cmake_uninstall.cmake.in b/host/cmake/cmake_uninstall.cmake.in
index 6031a6ca9..6031a6ca9 100644
--- a/host/cmake_uninstall.cmake.in
+++ b/host/cmake/cmake_uninstall.cmake.in
diff --git a/host/msvc/inttypes.h b/host/cmake/msvc/inttypes.h
index 1c2baa82e..1c2baa82e 100644
--- a/host/msvc/inttypes.h
+++ b/host/cmake/msvc/inttypes.h
diff --git a/host/msvc/stdint.h b/host/cmake/msvc/stdint.h
index 15333b467..15333b467 100644
--- a/host/msvc/stdint.h
+++ b/host/cmake/msvc/stdint.h
diff --git a/host/docs/images.rst b/host/docs/images.rst
index adfa6d530..c0645a821 100644
--- a/host/docs/images.rst
+++ b/host/docs/images.rst
@@ -14,6 +14,7 @@ The methods of loading images into the device varies among devices:
* **USRP2:** The user must manually write the images onto the USRP2 SD card.
* **USRP-N Series:** The user must manually transfer the images over ethernet.
* **USRP-E Series:** The host code will automatically load the FPGA at runtime.
+* **USRP-B Series:** The host code will automatically load the FPGA at runtime.
------------------------------------------------------------------------
Pre-built images
diff --git a/host/docs/usrp1.rst b/host/docs/usrp1.rst
index 97a8c3bb5..71b4f6779 100644
--- a/host/docs/usrp1.rst
+++ b/host/docs/usrp1.rst
@@ -34,24 +34,16 @@ Example device address string representations to specify non-standard firmware a
Specifying the subdevice to use
------------------------------------------------------------------------
The USRP1 has multiple daughterboard slots, known as slot A and slot B.
-The subdevice specification can be used to select
-the daughterboard and subdevice for each channel.
-For daughterboards with one one subdevice,
-the subdevice name may be left blank for automatic selection.
+The subdevice specification can be used to map an RF frontend to a DSP.
+An RF frontend is identified by the daughterboard slot name and subdevice name.
Ex: The subdev spec markup string to select a WBX on slot B.
-Notice the use of the blank subdevice name for automatic selection.
::
- B:
-
- -- OR --
-
B:0
Ex: The subdev spec markup string to select a BasicRX on slot B.
-Notice that the subdevice name is always specified in the 3 possible cases.
::
@@ -82,6 +74,10 @@ List of emulated features
* Receiving at a specific time
* Receiving a specific number of samples
* End of burst flags for transmit/receive
+* Notification on late stream command
+* Notification on late transmit packet
+* Notification on underflow or overflow
+* Notification on broken chain error
**Note:**
These emulated features rely on the host system's clock for timed operations,
@@ -90,10 +86,6 @@ and therefore may not have sufficient precision for the application.
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
List of missing features
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-* Notification on late stream command
-* Notification on late transmit packet
-* Notification on broken chain error
-* Notification on underflow or overflow
* Start of burst flags for transmit/receive
------------------------------------------------------------------------
diff --git a/host/docs/usrp2.rst b/host/docs/usrp2.rst
index 1b07834fb..025cdd198 100644
--- a/host/docs/usrp2.rst
+++ b/host/docs/usrp2.rst
@@ -246,60 +246,42 @@ Using the MIMO Cable
------------------------------------------------------------------------
The MIMO cable allows two USRP devices to share reference clocks,
time synchronization, and the ethernet interface.
+One of the devices will sink its clock and time references to the MIMO cable.
+This device will be referred to as the slave, and the other device, the master.
+
+* The slave device acquires the clock and time references from the master device.
+* The master and slave may be used individually or in a multi-device configuration.
+* External clocking is optional, and should only be supplied to the master device.
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Shared ethernet mode
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
In shared ethernet mode,
only one device in the configuration can be attached to the ethernet.
-This device will be referred to as the master, and the other device, the slave.
-* The master provides reference clock and time synchronization to the slave.
-* All data passing between the host and the slave is routed over the MIMO cable.
+* Clock reference, time reference, and data are communicated over the MIMO cable.
* Both master and slave must have different IPv4 addresses in the same subnet.
-* The master and slave may be used individually or in a multi-device configuration.
-* External clocking is optional, and should only be supplied to the master device.
-* The role of slave and master may be switched with the "mimo_mode" device address (see dual ethernet mode).
-
-Example device address string representation for 2 USRP2s with IPv4 addresses 192.168.10.2 (master) and 192.168.10.3 (slave)
-::
-
- -- Multi-device example --
-
- addr0=192.168.10.2, addr1=192.168.10.3
-
- -- Two single devices example --
-
- addr=192.168.10.2
-
- addr=192.168.10.3
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Dual ethernet mode
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
In dual ethernet mode,
both devices in the configuration must be attached to the ethernet.
-One of the devices in the configuration will be configured to provide synchronization.
-This device will be referred to as the master, and the other device, the slave.
-* The master provides reference clock and time synchronization to the slave.
-* The devices require the special device address argument "mimo_mode" set.
+* Only clock reference and time reference are communicated over the MIMO cable.
* Both master and slave must have different IPv4 addresses in different subnets.
-* The master and slave may be used individually or in a multi-device configuration.
-* External clocking is optional, and should only be supplied to the master device.
-Example device address string representation for 2 USRP2s with IPv4 addresses 192.168.10.2 (master) and 192.168.20.2 (slave)
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Configuring the slave
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+In order for the slave to synchronize to the master over MIMO cable,
+the following clock configuration must be set on the slave device:
::
- -- Multi-device example --
-
- addr0=192.168.10.2, mimo_mode0=master, addr1=192.168.20.2, mimo_mode1=slave
-
- -- Two single devices example --
-
- addr=192.168.10.2, mimo_mode=master
-
- addr=192.168.20.2, mimo_mode=slave
+ uhd::clock_config_t clock_config;
+ clock_config.ref_source = uhd::clock_config_t::REF_MIMO;
+ clock_config.pps_source = uhd::clock_config_t::PPS_MIMO;
+ usrp->set_clock_config(clock_config, slave_index);
------------------------------------------------------------------------
Hardware setup notes
@@ -406,11 +388,11 @@ In the single channel case, only one chain is ever used.
To receive from both channels,
the user must set the RX subdevice specification.
This hardware has only one daughterboard slot,
-which has been aptly named slot "0".
+which has been aptly named slot "A".
In the following example, a TVRX2 is installed.
Channel 0 is sourced from subdevice RX1,
channel 1 is sourced from subdevice RX2:
::
- usrp->set_rx_subdev_spec("0:RX1 0:RX2");
+ usrp->set_rx_subdev_spec("A:RX1 A:RX2");
diff --git a/host/docs/usrp_e1xx.rst b/host/docs/usrp_e1xx.rst
index fcaa57716..4ac9d133a 100644
--- a/host/docs/usrp_e1xx.rst
+++ b/host/docs/usrp_e1xx.rst
@@ -53,21 +53,6 @@ Example:
uhd_usrp_probe --args="master_clock_rate=52e6"
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-Clock rate recovery - unbricking
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-It is possible to set a clock rate such that the UHD can no longer communicate with the FPGA.
-When this occurs, it is necessary to use the usrp-e-utility to recover the clock generator.
-The recovery utility works by loading a special pass-through FPGA image so the computer
-can talk directly to the clock generator over a SPI interface.
-
-Run the following commands to restore the clock generator to a usable state:
-::
-
- cd <install-path>/share/uhd/usrp_e_utilities
- ./usrp-e-utility --fpga=../images/usrp_e100_pt_fpga.bin --reclk
-
-
------------------------------------------------------------------------
Clock Synchronization
------------------------------------------------------------------------
diff --git a/host/examples/CMakeLists.txt b/host/examples/CMakeLists.txt
index 10d1fddc3..bad7b72a6 100644
--- a/host/examples/CMakeLists.txt
+++ b/host/examples/CMakeLists.txt
@@ -24,7 +24,7 @@ SET(example_sources
rx_samples_to_file.cpp
rx_samples_to_udp.cpp
rx_timed_samples.cpp
- test_async_messages.cpp
+ test_messages.cpp
test_pps_input.cpp
tx_bursts.cpp
tx_samples_from_file.cpp
diff --git a/host/examples/rx_multi_samples.cpp b/host/examples/rx_multi_samples.cpp
index e820343ca..08b2d399d 100644
--- a/host/examples/rx_multi_samples.cpp
+++ b/host/examples/rx_multi_samples.cpp
@@ -44,7 +44,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
("nsamps", po::value<size_t>(&total_num_samps)->default_value(10000), "total number of samples to receive")
("rate", po::value<double>(&rate)->default_value(100e6/16), "rate of incoming samples")
("sync", po::value<std::string>(&sync)->default_value("now"), "synchronization method: now, pps")
- ("subdev", po::value<std::string>(&subdev)->default_value(""), "subdev spec (homogeneous across motherboards)")
+ ("subdev", po::value<std::string>(&subdev), "subdev spec (homogeneous across motherboards)")
("dilv", "specify to disable inner-loop verbose")
;
po::variables_map vm;
diff --git a/host/examples/test_async_messages.cpp b/host/examples/test_messages.cpp
index 7f922ed35..60d108184 100644
--- a/host/examples/test_async_messages.cpp
+++ b/host/examples/test_messages.cpp
@@ -18,6 +18,7 @@
#include <uhd/utils/thread_priority.hpp>
#include <uhd/utils/safe_main.hpp>
#include <uhd/utils/static.hpp>
+#include <uhd/types/stream_cmd.hpp>
#include <uhd/usrp/multi_usrp.hpp>
#include <boost/assign/list_of.hpp>
#include <boost/program_options.hpp>
@@ -31,6 +32,107 @@
namespace po = boost::program_options;
/*!
+ * Test the late command message:
+ * Issue a stream command with a time that is in the past.
+ * We expect to get an inline late command message.
+ */
+bool test_late_command_message(uhd::usrp::multi_usrp::sptr usrp){
+ std::cout << "Test late command message... " << std::flush;
+
+ usrp->set_time_now(uhd::time_spec_t(200.0)); //set time
+
+ uhd::stream_cmd_t stream_cmd(uhd::stream_cmd_t::STREAM_MODE_NUM_SAMPS_AND_DONE);
+ stream_cmd.num_samps = usrp->get_device()->get_max_recv_samps_per_packet();
+ stream_cmd.stream_now = false;
+ stream_cmd.time_spec = uhd::time_spec_t(100.0); //time in the past
+ usrp->issue_stream_cmd(stream_cmd);
+
+ std::vector<std::complex<float> > buff(usrp->get_device()->get_max_recv_samps_per_packet());
+ uhd::rx_metadata_t md;
+
+ const size_t nsamps = usrp->get_device()->recv(
+ &buff.front(), buff.size(), md,
+ uhd::io_type_t::COMPLEX_FLOAT32,
+ uhd::device::RECV_MODE_FULL_BUFF
+ );
+
+ switch(md.error_code){
+ case uhd::rx_metadata_t::ERROR_CODE_LATE_COMMAND:
+ std::cout << boost::format(
+ "success:\n"
+ " Got error code late command message.\n"
+ ) << std::endl;
+ return true;
+
+ case uhd::rx_metadata_t::ERROR_CODE_TIMEOUT:
+ std::cout << boost::format(
+ "failed:\n"
+ " Inline message recv timed out.\n"
+ ) << std::endl;
+ return false;
+
+ default:
+ std::cout << boost::format(
+ "failed:\n"
+ " Got unexpected error code 0x%x, nsamps %u.\n"
+ ) % md.error_code % nsamps << std::endl;
+ return false;
+ }
+}
+
+/*!
+ * Test the broken chain message:
+ * Issue a stream command with num samps and more.
+ * We expect to get an inline broken chain message.
+ */
+bool test_broken_chain_message(uhd::usrp::multi_usrp::sptr usrp){
+ std::cout << "Test broken chain message... " << std::flush;
+
+ uhd::stream_cmd_t stream_cmd(uhd::stream_cmd_t::STREAM_MODE_NUM_SAMPS_AND_MORE);
+ stream_cmd.stream_now = true;
+ stream_cmd.num_samps = usrp->get_device()->get_max_recv_samps_per_packet();
+ usrp->issue_stream_cmd(stream_cmd);
+
+ std::vector<std::complex<float> > buff(usrp->get_device()->get_max_recv_samps_per_packet());
+ uhd::rx_metadata_t md;
+
+ usrp->get_device()->recv( //once for the requested samples
+ &buff.front(), buff.size(), md,
+ uhd::io_type_t::COMPLEX_FLOAT32,
+ uhd::device::RECV_MODE_FULL_BUFF
+ );
+
+ usrp->get_device()->recv( //again for the inline message
+ &buff.front(), buff.size(), md,
+ uhd::io_type_t::COMPLEX_FLOAT32,
+ uhd::device::RECV_MODE_FULL_BUFF
+ );
+
+ switch(md.error_code){
+ case uhd::rx_metadata_t::ERROR_CODE_BROKEN_CHAIN:
+ std::cout << boost::format(
+ "success:\n"
+ " Got error code broken chain message.\n"
+ ) << std::endl;
+ return true;
+
+ case uhd::rx_metadata_t::ERROR_CODE_TIMEOUT:
+ std::cout << boost::format(
+ "failed:\n"
+ " Inline message recv timed out.\n"
+ ) << std::endl;
+ return false;
+
+ default:
+ std::cout << boost::format(
+ "failed:\n"
+ " Got unexpected error code 0x%x.\n"
+ ) % md.error_code << std::endl;
+ return false;
+ }
+}
+
+/*!
* Test the burst ack message:
* Send a burst of many samples that will fragment internally.
* We expect to get an burst ack async message.
@@ -169,9 +271,22 @@ bool test_time_error_message(uhd::usrp::multi_usrp::sptr usrp){
}
}
-void flush_async_md(uhd::usrp::multi_usrp::sptr usrp){
+void flush_async(uhd::usrp::multi_usrp::sptr usrp){
uhd::async_metadata_t async_md;
- while (usrp->get_device()->recv_async_msg(async_md, 1.0)){}
+ while (usrp->get_device()->recv_async_msg(async_md)){}
+}
+
+void flush_recv(uhd::usrp::multi_usrp::sptr usrp){
+ std::vector<std::complex<float> > buff(usrp->get_device()->get_max_recv_samps_per_packet());
+ uhd::rx_metadata_t md;
+
+ do{
+ usrp->get_device()->recv(
+ &buff.front(), buff.size(), md,
+ uhd::io_type_t::COMPLEX_FLOAT32,
+ uhd::device::RECV_MODE_FULL_BUFF
+ );
+ } while (md.error_code != uhd::rx_metadata_t::ERROR_CODE_TIMEOUT);
}
int UHD_SAFE_MAIN(int argc, char *argv[]){
@@ -179,7 +294,6 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
//variables to be set by po
std::string args;
- double rate;
size_t ntests;
//setup the program options
@@ -187,8 +301,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
desc.add_options()
("help", "help message")
("args", po::value<std::string>(&args)->default_value(""), "multi uhd device address args")
- ("rate", po::value<double>(&rate)->default_value(1.5e6), "rate of outgoing samples")
- ("ntests", po::value<size_t>(&ntests)->default_value(10), "number of tests to run")
+ ("ntests", po::value<size_t>(&ntests)->default_value(50), "number of tests to run")
;
po::variables_map vm;
po::store(po::parse_command_line(argc, argv, desc), vm);
@@ -196,7 +309,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
//print the help message
if (vm.count("help")){
- std::cout << boost::format("UHD Test Async Messages %s") % desc << std::endl;
+ std::cout << boost::format("UHD Test Messages %s") % desc << std::endl;
return ~0;
}
@@ -206,19 +319,16 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
uhd::usrp::multi_usrp::sptr usrp = uhd::usrp::multi_usrp::make(args);
std::cout << boost::format("Using Device: %s") % usrp->get_pp_string() << std::endl;
- //set the tx sample rate
- std::cout << boost::format("Setting TX Rate: %f Msps...") % (rate/1e6) << std::endl;
- usrp->set_tx_rate(rate);
- std::cout << boost::format("Actual TX Rate: %f Msps...") % (usrp->get_tx_rate()/1e6) << std::endl << std::endl;
-
//------------------------------------------------------------------
- // begin asyc messages test
+ // begin messages test
//------------------------------------------------------------------
static const uhd::dict<std::string, boost::function<bool(uhd::usrp::multi_usrp::sptr)> >
tests = boost::assign::map_list_of
("Test Burst ACK ", &test_burst_ack_message)
("Test Underflow ", &test_underflow_message)
("Test Time Error", &test_time_error_message)
+ ("Test Late Command", &test_late_command_message)
+ ("Test Broken Chain", &test_broken_chain_message)
;
//init result counts
@@ -229,10 +339,12 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
}
//run the tests, pick at random
+ std::srand(uhd::time_spec_t::get_system_time().get_full_secs());
for (size_t n = 0; n < ntests; n++){
std::string key = tests.keys()[std::rand() % tests.size()];
bool pass = tests[key](usrp);
- flush_async_md(usrp);
+ flush_async(usrp);
+ flush_recv(usrp);
//store result
if (pass) successes[key]++;
@@ -243,7 +355,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
std::cout << std::endl << "Summary:" << std::endl << std::endl;
BOOST_FOREACH(const std::string &key, tests.keys()){
std::cout << boost::format(
- "%s -> %3d successes, %3d failures"
+ "%s -> %3u successes, %3u failures"
) % key % successes[key] % failures[key] << std::endl;
}
diff --git a/host/include/uhd/CMakeLists.txt b/host/include/uhd/CMakeLists.txt
index 74dc4a7d6..49562a7a0 100644
--- a/host/include/uhd/CMakeLists.txt
+++ b/host/include/uhd/CMakeLists.txt
@@ -26,6 +26,8 @@ INSTALL(FILES
convert.hpp
device.hpp
exception.hpp
+ property_tree.ipp
+ property_tree.hpp
version.hpp
wax.hpp
DESTINATION ${INCLUDE_DIR}/uhd
diff --git a/host/include/uhd/property_tree.hpp b/host/include/uhd/property_tree.hpp
new file mode 100644
index 000000000..cd8cba7e5
--- /dev/null
+++ b/host/include/uhd/property_tree.hpp
@@ -0,0 +1,143 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// 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_PROPERTY_TREE_HPP
+#define INCLUDED_UHD_PROPERTY_TREE_HPP
+
+#include <uhd/config.hpp>
+#include <boost/utility.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/function.hpp>
+#include <boost/filesystem/path.hpp>
+#include <vector>
+
+namespace uhd{
+
+/*!
+ * A templated property interface for holding a value
+ * and registering callbacks when that value changes.
+ */
+template <typename T> class property : boost::noncopyable{
+public:
+ typedef boost::function<void(const T &)> subscriber_type;
+ typedef boost::function<T(void)> publisher_type;
+ typedef boost::function<T(const T &)> coercer_type;
+
+ /*!
+ * Register a coercer into the property.
+ * A coercer is a special subscribes that coerces the value.
+ * Only one coercer may be registered per property.
+ * Registering a coercer replaces the previous coercer.
+ * \param coercer the coercer callback function
+ * \return a reference to this property for chaining
+ */
+ virtual property<T> &coerce(const coercer_type &coercer) = 0;
+
+ /*!
+ * Register a publisher into the property.
+ * A publisher is a special callback the provides the value.
+ * Publishers are useful for creating read-only properties.
+ * Only one publisher may be registered per property.
+ * Registering a publisher replaces the previous publisher.
+ * \param publisher the publisher callback function
+ * \return a reference to this property for chaining
+ */
+ virtual property<T> &publish(const publisher_type &publisher) = 0;
+
+ /*!
+ * Register a subscriber into the property.
+ * All subscribers are called when the value changes.
+ * Once a subscriber is registered, it cannot be unregistered.
+ * \param subscriber the subscriber callback function
+ * \return a reference to this property for chaining
+ */
+ virtual property<T> &subscribe(const subscriber_type &subscriber) = 0;
+
+ /*!
+ * Update calls all subscribers w/ the current value.
+ * \return a reference to this property for chaining
+ */
+ virtual property<T> &update(void) = 0;
+
+ /*!
+ * Set the new value and call all subscribers.
+ * The coercer (when provided) is called initially,
+ * and the coerced value is used to set the subscribers.
+ * \param value the new value to set on this property
+ * \return a reference to this property for chaining
+ */
+ virtual property<T> &set(const T &value) = 0;
+
+ /*!
+ * Get the current value of this property.
+ * The publisher (when provided) yields the value,
+ * otherwise an internal shadow is used for the value.
+ * \return the current value in the property
+ */
+ virtual T get(void) const = 0;
+
+ /*!
+ * A property is empty if it has never been set.
+ * A property with a publisher is never empty.
+ * \return true if the property is empty
+ */
+ virtual bool empty(void) const = 0;
+};
+
+/*!
+ * The property tree provides a file system structure for accessing properties.
+ */
+class UHD_API property_tree : boost::noncopyable{
+public:
+ typedef boost::shared_ptr<property_tree> sptr;
+ typedef boost::filesystem::path path_type;
+
+ //! Create a new + empty property tree
+ static sptr make(void);
+
+ //! Get a subtree with a new root starting at path
+ virtual sptr subtree(const path_type &path) const = 0;
+
+ //! Remove a property or directory (recursive)
+ virtual void remove(const path_type &path) = 0;
+
+ //! True if the path exists in the tree
+ virtual bool exists(const path_type &path) const = 0;
+
+ //! Get an iterable to all things in the given path
+ virtual std::vector<std::string> list(const path_type &path) const = 0;
+
+ //! Create a new property entry in the tree
+ template <typename T> property<T> &create(const path_type &path);
+
+ //! Get access to a property in the tree
+ template <typename T> property<T> &access(const path_type &path);
+
+private:
+ //! Internal create property with wild-card type
+ virtual void _create(const path_type &path, const boost::shared_ptr<void> &prop) = 0;
+
+ //! Internal access property with wild-card type
+ virtual boost::shared_ptr<void> &_access(const path_type &path) const = 0;
+
+};
+
+} //namespace uhd
+
+#include <uhd/property_tree.ipp>
+
+#endif /* INCLUDED_UHD_PROPERTY_TREE_HPP */
diff --git a/host/include/uhd/property_tree.ipp b/host/include/uhd/property_tree.ipp
new file mode 100644
index 000000000..868cba475
--- /dev/null
+++ b/host/include/uhd/property_tree.ipp
@@ -0,0 +1,95 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// 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_PROPERTY_TREE_IPP
+#define INCLUDED_UHD_PROPERTY_TREE_IPP
+
+#include <uhd/exception.hpp>
+#include <boost/foreach.hpp>
+#include <vector>
+
+/***********************************************************************
+ * Implement templated property impl
+ **********************************************************************/
+namespace uhd{ namespace /*anon*/{
+
+template <typename T> class property_impl : public property<T>{
+public:
+
+ property<T> &coerce(const typename property<T>::coercer_type &coercer){
+ _coercer = coercer;
+ return *this;
+ }
+
+ property<T> &publish(const typename property<T>::publisher_type &publisher){
+ _publisher = publisher;
+ return *this;
+ }
+
+ property<T> &subscribe(const typename property<T>::subscriber_type &subscriber){
+ _subscribers.push_back(subscriber);
+ return *this;
+ }
+
+ property<T> &update(void){
+ this->set(this->get());
+ return *this;
+ }
+
+ property<T> &set(const T &value){
+ _value = boost::shared_ptr<T>(new T(_coercer.empty()? value : _coercer(value)));
+ BOOST_FOREACH(typename property<T>::subscriber_type &subscriber, _subscribers){
+ subscriber(*_value); //let errors propagate
+ }
+ return *this;
+ }
+
+ T get(void) const{
+ if (empty()) throw uhd::runtime_error("Cannot get() on an empty property");
+ return _publisher.empty()? *_value : _publisher();
+ }
+
+ bool empty(void) const{
+ return _publisher.empty() and _value.get() == NULL;
+ }
+
+private:
+ std::vector<typename property<T>::subscriber_type> _subscribers;
+ typename property<T>::publisher_type _publisher;
+ typename property<T>::coercer_type _coercer;
+ boost::shared_ptr<T> _value;
+};
+
+}} //namespace uhd::/*anon*/
+
+/***********************************************************************
+ * Implement templated methods for the property tree
+ **********************************************************************/
+namespace uhd{
+
+ template <typename T> property<T> &property_tree::create(const path_type &path){
+ this->_create(path, typename boost::shared_ptr<property<T> >(new property_impl<T>()));
+ return this->access<T>(path);
+ }
+
+ template <typename T> property<T> &property_tree::access(const path_type &path){
+ return *boost::static_pointer_cast<property<T> >(this->_access(path));
+ }
+
+} //namespace uhd
+
+#endif /* INCLUDED_UHD_PROPERTY_TREE_IPP */
diff --git a/host/include/uhd/types/serial.hpp b/host/include/uhd/types/serial.hpp
index 8281fd3ec..8a5ed1c32 100644
--- a/host/include/uhd/types/serial.hpp
+++ b/host/include/uhd/types/serial.hpp
@@ -19,6 +19,7 @@
#define INCLUDED_UHD_TYPES_SERIAL_HPP
#include <uhd/config.hpp>
+#include <boost/shared_ptr.hpp>
#include <boost/cstdint.hpp>
#include <vector>
@@ -43,6 +44,8 @@ namespace uhd{
*/
class UHD_API i2c_iface{
public:
+ typedef boost::shared_ptr<i2c_iface> sptr;
+
/*!
* Write bytes over the i2c.
* \param addr the address
@@ -123,6 +126,8 @@ namespace uhd{
*/
class UHD_API spi_iface{
public:
+ typedef boost::shared_ptr<spi_iface> sptr;
+
/*!
* Perform a spi transaction.
* \param which_slave the slave device number
@@ -170,6 +175,28 @@ namespace uhd{
);
};
+ /*!
+ * UART interface to write and read bytes.
+ */
+ class UHD_API uart_iface{
+ public:
+ typedef boost::shared_ptr<uart_iface> sptr;
+
+ /*!
+ * Write to a serial port.
+ * \param dev which UART to write to
+ * \param buf the data to write
+ */
+ virtual void write_uart(boost::uint8_t dev, const std::string &buf) = 0;
+
+ /*!
+ * Read from a serial port.
+ * \param dev which UART to read from
+ * \return the data read from the serial port
+ */
+ virtual std::string read_uart(boost::uint8_t dev) = 0;
+ };
+
} //namespace uhd
#endif /* INCLUDED_UHD_TYPES_SERIAL_HPP */
diff --git a/host/include/uhd/usrp/CMakeLists.txt b/host/include/uhd/usrp/CMakeLists.txt
index e441433fd..ba38a67ea 100644
--- a/host/include/uhd/usrp/CMakeLists.txt
+++ b/host/include/uhd/usrp/CMakeLists.txt
@@ -17,13 +17,6 @@
INSTALL(FILES
- #### props headers ###
- codec_props.hpp
- dboard_props.hpp
- device_props.hpp
- dsp_props.hpp
- mboard_props.hpp
- subdev_props.hpp
#### dboard headers ###
dboard_base.hpp
@@ -33,12 +26,9 @@ INSTALL(FILES
dboard_manager.hpp
### utilities ###
- dsp_utils.hpp
gps_ctrl.hpp
mboard_eeprom.hpp
- misc_utils.hpp
subdev_spec.hpp
- tune_helper.hpp
### interfaces ###
single_usrp.hpp
diff --git a/host/include/uhd/usrp/codec_props.hpp b/host/include/uhd/usrp/codec_props.hpp
deleted file mode 100644
index b0a79e3f6..000000000
--- a/host/include/uhd/usrp/codec_props.hpp
+++ /dev/null
@@ -1,42 +0,0 @@
-//
-// Copyright 2010-2011 Ettus Research LLC
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// 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, //ro, std::string
- CODEC_PROP_OTHERS, //ro, prop_names_t
- CODEC_PROP_GAIN_I, //rw, double
- CODEC_PROP_GAIN_Q , //rw, double
- CODEC_PROP_GAIN_RANGE, //ro, gain_range_t
- CODEC_PROP_GAIN_NAMES //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 9b75d791f..7e9557a95 100644
--- a/host/include/uhd/usrp/dboard_base.hpp
+++ b/host/include/uhd/usrp/dboard_base.hpp
@@ -28,6 +28,43 @@
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{
+ SUBDEV_PROP_NAME, //ro, std::string
+ SUBDEV_PROP_OTHERS, //ro, prop_names_t
+ SUBDEV_PROP_SENSOR, //ro, sensor_value_t
+ SUBDEV_PROP_SENSOR_NAMES, //ro, prop_names_t
+ SUBDEV_PROP_GAIN, //rw, double
+ SUBDEV_PROP_GAIN_RANGE, //ro, gain_range_t
+ SUBDEV_PROP_GAIN_NAMES, //ro, prop_names_t
+ SUBDEV_PROP_FREQ, //rw, double
+ SUBDEV_PROP_FREQ_RANGE, //ro, freq_range_t
+ SUBDEV_PROP_ANTENNA, //rw, std::string
+ SUBDEV_PROP_ANTENNA_NAMES, //ro, prop_names_t
+ SUBDEV_PROP_CONNECTION, //ro, subdev_conn_t
+ SUBDEV_PROP_ENABLED, //rw, bool
+ SUBDEV_PROP_USE_LO_OFFSET, //ro, bool
+ SUBDEV_PROP_BANDWIDTH //rw, double
+ };
+
/*!
* A daughter board dboard_base class for all dboards.
* Only other dboard dboard_base classes should inherit this.
diff --git a/host/include/uhd/usrp/dboard_eeprom.hpp b/host/include/uhd/usrp/dboard_eeprom.hpp
index 394d71dd6..f0190e233 100644
--- a/host/include/uhd/usrp/dboard_eeprom.hpp
+++ b/host/include/uhd/usrp/dboard_eeprom.hpp
@@ -50,7 +50,7 @@ struct UHD_API dboard_eeprom_t{
* \param iface the serial interface with i2c
* \param addr the i2c address for the eeprom
*/
- void store(i2c_iface &iface, boost::uint8_t addr);
+ void store(i2c_iface &iface, boost::uint8_t addr) const;
};
diff --git a/host/include/uhd/usrp/dboard_manager.hpp b/host/include/uhd/usrp/dboard_manager.hpp
index 3c41c65a8..091769a5c 100644
--- a/host/include/uhd/usrp/dboard_manager.hpp
+++ b/host/include/uhd/usrp/dboard_manager.hpp
@@ -19,6 +19,7 @@
#define INCLUDED_UHD_USRP_DBOARD_MANAGER_HPP
#include <uhd/config.hpp>
+#include <uhd/property_tree.hpp>
#include <uhd/utils/props.hpp>
#include <uhd/usrp/dboard_base.hpp>
#include <uhd/usrp/dboard_id.hpp>
@@ -36,6 +37,11 @@ class UHD_API dboard_manager : boost::noncopyable{
public:
typedef boost::shared_ptr<dboard_manager> sptr;
+ //! It does what it says...
+ static void populate_prop_tree_from_subdev(
+ property_tree::sptr subtree, wax::obj subdev
+ );
+
//dboard constructor (each dboard should have a ::make with this signature)
typedef dboard_base::sptr(*dboard_ctor_t)(dboard_base::ctor_args_t);
diff --git a/host/include/uhd/usrp/dboard_props.hpp b/host/include/uhd/usrp/dboard_props.hpp
deleted file mode 100644
index 29211ec8c..000000000
--- a/host/include/uhd/usrp/dboard_props.hpp
+++ /dev/null
@@ -1,43 +0,0 @@
-//
-// Copyright 2010-2011 Ettus Research LLC
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// 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_DBOARD_PROPS_HPP
-#define INCLUDED_UHD_USRP_DBOARD_PROPS_HPP
-
-#include <uhd/utils/props.hpp>
-
-namespace uhd{ namespace usrp{
-
- /*!
- * 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, //ro, std::string
- DBOARD_PROP_SUBDEV, //ro, wax::obj
- DBOARD_PROP_SUBDEV_NAMES, //ro, prop_names_t
- DBOARD_PROP_DBOARD_EEPROM, //rw, dboard_eeprom_t
- DBOARD_PROP_GBOARD_EEPROM, //rw, dboard_eeprom_t
- DBOARD_PROP_DBOARD_IFACE, //ro, dboard_iface::sptr
- DBOARD_PROP_CODEC, //ro, wax::obj
- DBOARD_PROP_GAIN_GROUP //ro, gain_group
- };
-
-}} //namespace
-
-#endif /* INCLUDED_UHD_USRP_DBOARD_PROPS_HPP */
diff --git a/host/include/uhd/usrp/dsp_props.hpp b/host/include/uhd/usrp/dsp_props.hpp
deleted file mode 100644
index e68e11deb..000000000
--- a/host/include/uhd/usrp/dsp_props.hpp
+++ /dev/null
@@ -1,50 +0,0 @@
-//
-// Copyright 2010-2011 Ettus Research LLC
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// 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_DSP_PROPS_HPP
-#define INCLUDED_UHD_USRP_DSP_PROPS_HPP
-
-#include <uhd/utils/props.hpp>
-
-namespace uhd{ namespace usrp{
-
- /*!
- * Possible device dsp properties:
- * A dsp is a black box fpga component found between
- * the over-the-wire data and the codec pins.
- *
- * The host rate can be modified to control resampling.
- * Resampling can take the form of decimation, interpolation,
- * or more complex fractional resampling techniques.
- * As usual, read back the host rate after setting it
- * to get the actual rate that was set (implementation dependent).
- *
- * A dsp can also shift the digital stream in frequency.
- * Set the shift property and read it back to get actual shift.
- */
- enum dsp_prop_t{
- DSP_PROP_NAME, //ro, std::string
- DSP_PROP_OTHERS, //ro, prop_names_t
- DSP_PROP_STREAM_CMD, //wo, stream_cmd_t
- DSP_PROP_FREQ_SHIFT, //rw, double Hz
- DSP_PROP_CODEC_RATE, //ro, double Sps
- DSP_PROP_HOST_RATE //rw, double Sps
- };
-
-}} //namespace
-
-#endif /* INCLUDED_UHD_USRP_DSP_PROPS_HPP */
diff --git a/host/include/uhd/usrp/dsp_utils.hpp b/host/include/uhd/usrp/dsp_utils.hpp
deleted file mode 100644
index 5b81ce322..000000000
--- a/host/include/uhd/usrp/dsp_utils.hpp
+++ /dev/null
@@ -1,96 +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_USRP_DSP_UTILS_HPP
-#define INCLUDED_UHD_USRP_DSP_UTILS_HPP
-
-#include <uhd/config.hpp>
-#include <uhd/types/stream_cmd.hpp>
-#include <uhd/usrp/subdev_props.hpp>
-#include <boost/cstdint.hpp>
-
-namespace uhd{ namespace usrp{
-
-namespace dsp_type1{
-
- /*!
- * Calculate the rx mux word from properties.
- * \param subdev_conn the subdev connection type
- * \return the 32-bit rx mux control word
- */
- UHD_API boost::uint32_t calc_rx_mux_word(subdev_conn_t subdev_conn);
-
- /*!
- * Calculate the tx mux word from properties.
- * \param subdev_conn the subdev connection type
- * \return the 32-bit tx mux control word
- */
- UHD_API boost::uint32_t calc_tx_mux_word(subdev_conn_t subdev_conn);
-
- /*!
- * Calculate the cordic word from the frequency and clock rate.
- * The frequency will be set to the actual (possible) frequency.
- *
- * \param freq the requested frequency in Hz
- * \param codec_rate the dsp codec rate in Hz
- * \return the 32-bit cordic control word
- */
- UHD_API boost::uint32_t calc_cordic_word_and_update(
- double &freq, double codec_rate
- );
-
- /*!
- * Calculate the CIC filter word from the rate.
- * Check if requested decim/interp rate is:
- * multiple of 4, enable two halfband filters
- * multiple of 2, enable one halfband filter
- * handle remainder in CIC
- *
- * \param rate the requested rate in Sps
- * \return the 32-bit cic filter control word
- */
- UHD_API boost::uint32_t calc_cic_filter_word(unsigned rate);
-
- /*!
- * Calculate the IQ scale factor word from I and Q components.
- * \param i the I component of the scalar
- * \param q the Q component of the scalar
- * \return the 32-bit scale factor control word
- */
- UHD_API boost::uint32_t calc_iq_scale_word(
- boost::int16_t i, boost::int16_t q
- );
-
- /*!
- * Calculate the IQ scale factor word from the rate.
- * \param rate the requested rate in Sps
- * \return the 32-bit scale factor control word
- */
- UHD_API boost::uint32_t calc_iq_scale_word(unsigned rate);
-
- /*!
- * Calculate the stream command word from the stream command struct.
- * \param stream_cmd the requested stream command with mode, flags, timestamp
- * \return the 32-bit stream command word
- */
- UHD_API boost::uint32_t calc_stream_cmd_word(const stream_cmd_t &stream_cmd);
-
-} //namespace dsp_type1
-
-}} //namespace
-
-#endif /* INCLUDED_UHD_USRP_DSP_UTILS_HPP */
diff --git a/host/include/uhd/usrp/mboard_eeprom.hpp b/host/include/uhd/usrp/mboard_eeprom.hpp
index 52363b95c..ea66bb2e0 100644
--- a/host/include/uhd/usrp/mboard_eeprom.hpp
+++ b/host/include/uhd/usrp/mboard_eeprom.hpp
@@ -56,7 +56,7 @@ namespace uhd{ namespace usrp{
* \param iface the interface to i2c
* \param map the map type enum
*/
- void commit(i2c_iface &iface, map_type map);
+ void commit(i2c_iface &iface, map_type map) const;
};
diff --git a/host/include/uhd/usrp/mboard_iface.hpp b/host/include/uhd/usrp/mboard_iface.hpp
index 784fbc7c5..bbee8f2de 100644
--- a/host/include/uhd/usrp/mboard_iface.hpp
+++ b/host/include/uhd/usrp/mboard_iface.hpp
@@ -33,7 +33,7 @@ namespace uhd{ namespace usrp{
* Provides a set of functions to implementation layer.
* Including spi, peek, poke, control...
*/
-class mboard_iface : public uhd::i2c_iface, public uhd::spi_iface {
+class mboard_iface : public uhd::i2c_iface, public uhd::spi_iface, public uhd::uart_iface {
public:
typedef boost::shared_ptr<mboard_iface> sptr;
/*!
@@ -64,20 +64,6 @@ public:
*/
virtual boost::uint16_t peek16(boost::uint32_t addr) = 0;
- /*!
- * Write to a serial port.
- * \param dev which UART to write to
- * \param buf the data to write
- */
- virtual void write_uart(boost::uint8_t dev, const std::string &buf) = 0;
-
- /*!
- * Read from a serial port.
- * \param dev which UART to read from
- * \return the data read from the serial port
- */
- virtual std::string read_uart(boost::uint8_t dev) = 0;
-
};
}}
diff --git a/host/include/uhd/usrp/mboard_props.hpp b/host/include/uhd/usrp/mboard_props.hpp
deleted file mode 100644
index a2580954e..000000000
--- a/host/include/uhd/usrp/mboard_props.hpp
+++ /dev/null
@@ -1,56 +0,0 @@
-//
-// Copyright 2010-2011 Ettus Research LLC
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// 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_MBOARD_PROPS_HPP
-#define INCLUDED_UHD_USRP_MBOARD_PROPS_HPP
-
-#include <uhd/utils/props.hpp>
-
-namespace uhd{ namespace usrp{
-
- /*!
- * Possible device mboard properties:
- * The general mboard properties are listed below.
- * Custom properties can be identified with a string
- * and discovered though the others property.
- */
- enum mboard_prop_t{
- MBOARD_PROP_NAME, //ro, std::string
- MBOARD_PROP_OTHERS, //ro, prop_names_t
- MBOARD_PROP_SENSOR, //ro, sensor_value_t
- MBOARD_PROP_SENSOR_NAMES, //ro, prop_names_t
- MBOARD_PROP_CLOCK_RATE, //rw, double
- MBOARD_PROP_RX_DSP, //ro, wax::obj
- MBOARD_PROP_RX_DSP_NAMES, //ro, prop_names_t
- MBOARD_PROP_TX_DSP, //ro, wax::obj
- MBOARD_PROP_TX_DSP_NAMES, //ro, prop_names_t
- MBOARD_PROP_RX_DBOARD, //ro, wax::obj
- MBOARD_PROP_RX_DBOARD_NAMES, //ro, prop_names_t
- MBOARD_PROP_TX_DBOARD, //ro, wax::obj
- MBOARD_PROP_TX_DBOARD_NAMES, //ro, prop_names_t
- MBOARD_PROP_RX_SUBDEV_SPEC, //rw, subdev_spec_t
- MBOARD_PROP_TX_SUBDEV_SPEC, //rw, subdev_spec_t
- MBOARD_PROP_CLOCK_CONFIG, //rw, clock_config_t
- MBOARD_PROP_TIME_NOW, //rw, time_spec_t
- MBOARD_PROP_TIME_PPS, //wo, time_spec_t
- MBOARD_PROP_EEPROM_MAP, //wr, mboard_eeprom_t
- MBOARD_PROP_IFACE, //ro, mboard_iface::sptr
- };
-
-}} //namespace
-
-#endif /* INCLUDED_UHD_USRP_MBOARD_PROPS_HPP */
diff --git a/host/include/uhd/usrp/misc_utils.hpp b/host/include/uhd/usrp/misc_utils.hpp
deleted file mode 100644
index 37860a1a5..000000000
--- a/host/include/uhd/usrp/misc_utils.hpp
+++ /dev/null
@@ -1,71 +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_USRP_MISC_UTILS_HPP
-#define INCLUDED_UHD_USRP_MISC_UTILS_HPP
-
-#include <uhd/config.hpp>
-#include <uhd/wax.hpp>
-#include <uhd/usrp/dboard_id.hpp>
-#include <uhd/usrp/subdev_spec.hpp>
-#include <uhd/utils/gain_group.hpp>
-
-namespace uhd{ namespace usrp{
-
- /*!
- * Different policies for gain group prioritization.
- */
- enum gain_group_policy_t{
- GAIN_GROUP_POLICY_RX = 'R',
- GAIN_GROUP_POLICY_TX = 'T'
- };
-
- /*!
- * Create a gain group that represents the subdevice and its codec.
- * \param dboard_id the dboard id for this subdevice
- * \param subdev the object with subdevice properties
- * \param codec the object with codec properties
- * \param gain_group_policy the policy to use
- */
- UHD_API gain_group::sptr make_gain_group(
- const dboard_id_t &dboard_id,
- wax::obj subdev, wax::obj codec,
- gain_group_policy_t gain_group_policy
- );
-
- /*!
- * Verify the rx subdevice specification.
- * If the subdev spec if empty, automatically fill it.
- * \param subdev_spec the subdev spec to verify/fill
- * \param mboard the motherboard properties object
- * \throw exception when the subdev spec is invalid
- */
- UHD_API void verify_rx_subdev_spec(subdev_spec_t &subdev_spec, wax::obj mboard);
-
- /*!
- * Verify the tx subdevice specification.
- * If the subdev spec if empty, automatically fill it.
- * \param subdev_spec the subdev spec to verify/fill
- * \param mboard the motherboard properties object
- * \throw exception when the subdev spec is invalid
- */
- UHD_API void verify_tx_subdev_spec(subdev_spec_t &subdev_spec, wax::obj mboard);
-
-}} //namespace
-
-#endif /* INCLUDED_UHD_USRP_MISC_UTILS_HPP */
-
diff --git a/host/include/uhd/usrp/subdev_props.hpp b/host/include/uhd/usrp/subdev_props.hpp
deleted file mode 100644
index 40b339703..000000000
--- a/host/include/uhd/usrp/subdev_props.hpp
+++ /dev/null
@@ -1,64 +0,0 @@
-//
-// Copyright 2010-2011 Ettus Research LLC
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// 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_PROPS_HPP
-#define INCLUDED_UHD_USRP_SUBDEV_PROPS_HPP
-
-#include <uhd/utils/props.hpp>
-
-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{
- SUBDEV_PROP_NAME, //ro, std::string
- SUBDEV_PROP_OTHERS, //ro, prop_names_t
- SUBDEV_PROP_SENSOR, //ro, sensor_value_t
- SUBDEV_PROP_SENSOR_NAMES, //ro, prop_names_t
- SUBDEV_PROP_GAIN, //rw, double
- SUBDEV_PROP_GAIN_RANGE, //ro, gain_range_t
- SUBDEV_PROP_GAIN_NAMES, //ro, prop_names_t
- SUBDEV_PROP_FREQ, //rw, double
- SUBDEV_PROP_FREQ_RANGE, //ro, freq_range_t
- SUBDEV_PROP_ANTENNA, //rw, std::string
- SUBDEV_PROP_ANTENNA_NAMES, //ro, prop_names_t
- SUBDEV_PROP_CONNECTION, //ro, subdev_conn_t
- SUBDEV_PROP_ENABLED, //rw, bool
- SUBDEV_PROP_USE_LO_OFFSET, //ro, bool
- SUBDEV_PROP_BANDWIDTH //rw, double
- };
-
-}} //namespace
-
-#endif /* INCLUDED_UHD_USRP_SUBDEV_PROPS_HPP */
diff --git a/host/include/uhd/usrp/subdev_spec.hpp b/host/include/uhd/usrp/subdev_spec.hpp
index b189724c9..62c1fc177 100644
--- a/host/include/uhd/usrp/subdev_spec.hpp
+++ b/host/include/uhd/usrp/subdev_spec.hpp
@@ -62,11 +62,6 @@ namespace uhd{ namespace usrp{
* The markup-string is a whitespace separated list of dboard:subdev pairs.
* The first pair represents the subdevice for channel zero,
* the second pair represents the subdevice for channel one, and so on.
- *
- * Special handling for empty conditions:
- * - An empty subdevice specification means: select the first subdevice found in the configuration
- * - An empty daughterboard name means: select the only daughterboard slot or error if multiple exist
- * - An empty subdevice name means: select the only subdevice on that board or error if multiple exist
*/
class UHD_API subdev_spec_t : public std::vector<subdev_spec_pair_t>{
public:
diff --git a/host/include/uhd/usrp/tune_helper.hpp b/host/include/uhd/usrp/tune_helper.hpp
deleted file mode 100644
index 0d468a4e2..000000000
--- a/host/include/uhd/usrp/tune_helper.hpp
+++ /dev/null
@@ -1,78 +0,0 @@
-//
-// Copyright 2010-2011 Ettus Research LLC
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// 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_TUNE_HELPER_HPP
-#define INCLUDED_UHD_USRP_TUNE_HELPER_HPP
-
-#include <uhd/config.hpp>
-#include <uhd/wax.hpp>
-#include <uhd/types/tune_request.hpp>
-#include <uhd/types/tune_result.hpp>
-
-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 mboard dsp object with properties
- * \param tune_request tune request instructions
- * \return a tune result struct
- */
- UHD_API tune_result_t tune_rx_subdev_and_dsp(
- wax::obj subdev, wax::obj ddc, const tune_request_t &tune_request
- );
-
- /*!
- * Calculate the overall frequency from the combination of dboard IF and DDC shift.
- * \param subdev the dboard subdevice object with properties
- * \param ddc the mboard dsp object with properties
- * \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:
- * 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 tune_request tune request instructions
- * \return a tune result struct
- */
- UHD_API tune_result_t tune_tx_subdev_and_dsp(
- wax::obj subdev, wax::obj duc, const tune_request_t &tune_request
- );
-
- /*!
- * Calculate the overall frequency from the combination of dboard IF and DUC shift.
- * \param subdev the dboard subdevice object with properties
- * \param duc the mboard dsp object with properties
- * \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
- );
-
-}}
-
-#endif /* INCLUDED_UHD_USRP_TUNE_HELPER_HPP */
diff --git a/host/include/uhd/utils/CMakeLists.txt b/host/include/uhd/utils/CMakeLists.txt
index 88a0e612b..0bf98fb67 100644
--- a/host/include/uhd/utils/CMakeLists.txt
+++ b/host/include/uhd/utils/CMakeLists.txt
@@ -30,6 +30,7 @@ INSTALL(FILES
safe_call.hpp
safe_main.hpp
static.hpp
+ tasks.hpp
thread_priority.hpp
DESTINATION ${INCLUDE_DIR}/uhd/utils
COMPONENT headers
diff --git a/host/include/uhd/utils/tasks.hpp b/host/include/uhd/utils/tasks.hpp
new file mode 100644
index 000000000..38b2bddf0
--- /dev/null
+++ b/host/include/uhd/utils/tasks.hpp
@@ -0,0 +1,53 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// 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_TASKS_HPP
+#define INCLUDED_UHD_UTILS_TASKS_HPP
+
+#include <uhd/config.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/function.hpp>
+#include <boost/utility.hpp>
+
+namespace uhd{
+
+ class task : boost::noncopyable{
+ public:
+ typedef boost::shared_ptr<task> sptr;
+ typedef boost::function<void(void)> task_fcn_type;
+
+ /*!
+ * Create a new task object with function callback.
+ * The task function callback will be run in a loop.
+ * until the thread is interrupted by the deconstructor.
+ *
+ * A task should return in a reasonable amount of time
+ * or may block forever under the following conditions:
+ * - The blocking call is interruptible.
+ * - The task polls the interrupt condition.
+ *
+ * \param task_fcn the task callback function
+ * \return a new task object
+ */
+ static sptr make(const task_fcn_type &task_fcn);
+
+ };
+
+} //namespace uhd
+
+#endif /* INCLUDED_UHD_UTILS_TASKS_HPP */
+
diff --git a/host/lib/CMakeLists.txt b/host/lib/CMakeLists.txt
index ebb211566..60ddbce5b 100644
--- a/host/lib/CMakeLists.txt
+++ b/host/lib/CMakeLists.txt
@@ -89,6 +89,7 @@ SET_SOURCE_FILES_PROPERTIES(
LIBUHD_APPEND_SOURCES(
${CMAKE_CURRENT_SOURCE_DIR}/device.cpp
${CMAKE_CURRENT_SOURCE_DIR}/exception.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/property_tree.cpp
${CMAKE_CURRENT_SOURCE_DIR}/version.cpp
${CMAKE_CURRENT_SOURCE_DIR}/wax.cpp
)
diff --git a/host/lib/property_tree.cpp b/host/lib/property_tree.cpp
new file mode 100644
index 000000000..469d59e0d
--- /dev/null
+++ b/host/lib/property_tree.cpp
@@ -0,0 +1,132 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// 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/property_tree.hpp>
+#include <uhd/types/dict.hpp>
+#include <boost/foreach.hpp>
+#include <boost/thread/mutex.hpp>
+#include <boost/make_shared.hpp>
+#include <iostream>
+
+class property_tree_impl : public uhd::property_tree{
+public:
+
+ property_tree_impl(const path_type &root = path_type()):
+ _root(root)
+ {
+ _guts = boost::make_shared<tree_guts_type>();
+ }
+
+ sptr subtree(const path_type &path_) const{
+ const path_type path = _root / path_;
+ boost::mutex::scoped_lock lock(_guts->mutex);
+
+ property_tree_impl *subtree = new property_tree_impl(path);
+ subtree->_guts = this->_guts; //copy the guts sptr
+ return sptr(subtree);
+ }
+
+ void remove(const path_type &path_){
+ const path_type path = _root / path_;
+ boost::mutex::scoped_lock lock(_guts->mutex);
+
+ node_type *parent = NULL;
+ node_type *node = &_guts->root;
+ BOOST_FOREACH(const std::string &branch, path){
+ if (not node->has_key(branch)) throw_path_not_found(path);
+ parent = node;
+ node = &(*node)[branch];
+ }
+ if (parent == NULL) throw uhd::runtime_error("Cannot uproot");
+ parent->pop(path.leaf());
+ }
+
+ bool exists(const path_type &path_) const{
+ const path_type path = _root / path_;
+ boost::mutex::scoped_lock lock(_guts->mutex);
+
+ node_type *node = &_guts->root;
+ BOOST_FOREACH(const std::string &branch, path){
+ if (not node->has_key(branch)) return false;
+ node = &(*node)[branch];
+ }
+ return true;
+ }
+
+ std::vector<std::string> list(const path_type &path_) const{
+ const path_type path = _root / path_;
+ boost::mutex::scoped_lock lock(_guts->mutex);
+
+ node_type *node = &_guts->root;
+ BOOST_FOREACH(const std::string &branch, path){
+ if (not node->has_key(branch)) throw_path_not_found(path);
+ node = &(*node)[branch];
+ }
+
+ return node->keys();
+ }
+
+ void _create(const path_type &path_, const boost::shared_ptr<void> &prop){
+ const path_type path = _root / path_;
+ boost::mutex::scoped_lock lock(_guts->mutex);
+
+ node_type *node = &_guts->root;
+ BOOST_FOREACH(const std::string &branch, path){
+ if (not node->has_key(branch)) (*node)[branch] = node_type();
+ node = &(*node)[branch];
+ }
+ if (node->prop.get() != NULL) throw uhd::runtime_error("Cannot create! Property already exists at: " + path.string());
+ node->prop = prop;
+ }
+
+ boost::shared_ptr<void> &_access(const path_type &path_) const{
+ const path_type path = _root / path_;
+ boost::mutex::scoped_lock lock(_guts->mutex);
+
+ node_type *node = &_guts->root;
+ BOOST_FOREACH(const std::string &branch, path){
+ if (not node->has_key(branch)) throw_path_not_found(path);
+ node = &(*node)[branch];
+ }
+ if (node->prop.get() == NULL) throw uhd::runtime_error("Cannot access! Property uninitialized at: " + path.string());
+ return node->prop;
+ }
+
+private:
+ void throw_path_not_found(const path_type &path) const{
+ throw uhd::lookup_error("Path not found in tree: " + path.string());
+ }
+
+ //basic structural node element
+ struct node_type : uhd::dict<std::string, node_type>{
+ boost::shared_ptr<void> prop;
+ };
+
+ //tree guts which may be referenced in a subtree
+ struct tree_guts_type{
+ node_type root;
+ boost::mutex mutex;
+ };
+
+ //members, the tree and root prefix
+ boost::shared_ptr<tree_guts_type> _guts;
+ const path_type _root;
+};
+
+uhd::property_tree::sptr uhd::property_tree::make(void){
+ return sptr(new property_tree_impl());
+}
diff --git a/host/lib/transport/libusb1_base.cpp b/host/lib/transport/libusb1_base.cpp
index 6d4df7875..9b4290c08 100644
--- a/host/lib/transport/libusb1_base.cpp
+++ b/host/lib/transport/libusb1_base.cpp
@@ -206,7 +206,7 @@ libusb::device_handle::sptr libusb::device_handle::get_cached_handle(device::spt
handles[dev->get()] = new_handle;
return new_handle;
}
- catch(const uhd::exception &e){
+ catch(const uhd::exception &){
std::cerr << "USB open failed: see the application notes for your device." << std::endl;
throw;
}
diff --git a/host/lib/transport/libusb1_control.cpp b/host/lib/transport/libusb1_control.cpp
index f903907d0..bce3d4b0b 100644
--- a/host/lib/transport/libusb1_control.cpp
+++ b/host/lib/transport/libusb1_control.cpp
@@ -17,6 +17,7 @@
#include "libusb1_base.hpp"
#include <uhd/transport/usb_control.hpp>
+#include <boost/thread/mutex.hpp>
using namespace uhd::transport;
@@ -40,6 +41,7 @@ public:
unsigned char *buff,
boost::uint16_t length
){
+ boost::mutex::scoped_lock lock(_mutex);
return libusb_control_transfer(_handle->get(),
request_type,
request,
@@ -52,6 +54,7 @@ public:
private:
libusb::device_handle::sptr _handle;
+ boost::mutex _mutex;
};
/***********************************************************************
diff --git a/host/lib/transport/libusb1_zero_copy.cpp b/host/lib/transport/libusb1_zero_copy.cpp
index f781f890d..0fa856d34 100644
--- a/host/lib/transport/libusb1_zero_copy.cpp
+++ b/host/lib/transport/libusb1_zero_copy.cpp
@@ -21,11 +21,11 @@
#include <uhd/transport/buffer_pool.hpp>
#include <uhd/utils/thread_priority.hpp>
#include <uhd/utils/msg.hpp>
+#include <uhd/utils/tasks.hpp>
#include <uhd/exception.hpp>
#include <boost/function.hpp>
#include <boost/foreach.hpp>
#include <boost/thread/thread.hpp>
-#include <boost/thread/barrier.hpp>
#include <list>
using namespace uhd;
@@ -202,12 +202,10 @@ public:
}
//spawn the event handler threads
- size_t concurrency = hints.cast<size_t>("concurrency_hint", 1);
- boost::barrier spawn_barrier(concurrency+1);
- for (size_t i = 0; i < concurrency; i++) _thread_group.create_thread(
- boost::bind(&libusb_zero_copy_impl::run_event_loop, this, boost::ref(spawn_barrier))
- );
- spawn_barrier.wait();
+ const size_t concurrency = hints.cast<size_t>("concurrency_hint", 1);
+ for (size_t i = 0; i < concurrency; i++) _event_loop_tasks.push_back(task::make(
+ boost::bind(&libusb_zero_copy_impl::run_event_loop, this)
+ ));
}
~libusb_zero_copy_impl(void){
@@ -221,9 +219,6 @@ public:
boost::this_thread::sleep(boost::posix_time::milliseconds(10));
}
}
- //shutdown the threads
- _thread_group.interrupt_all();
- _thread_group.join_all();
}
managed_recv_buffer::sptr get_recv_buff(double timeout){
@@ -275,20 +270,17 @@ private:
std::list<libusb_transfer *> _all_luts;
//! event handler threads
- boost::thread_group _thread_group;
+ std::list<task::sptr> _event_loop_tasks;
- void run_event_loop(boost::barrier &spawn_barrier){
- spawn_barrier.wait();
+ void run_event_loop(void){
set_thread_priority_safe();
libusb_context *context = libusb::session::get_global_session()->get_context();
- try{
- while (not boost::this_thread::interruption_requested()){
- timeval tv;
- tv.tv_sec = 0;
- tv.tv_usec = 100000; //100ms
- libusb_handle_events_timeout(context, &tv);
- }
- } catch(const boost::thread_interrupted &){}
+ while (not boost::this_thread::interruption_requested()){
+ timeval tv;
+ tv.tv_sec = 0;
+ tv.tv_usec = 100000; //100ms
+ libusb_handle_events_timeout(context, &tv);
+ }
}
};
diff --git a/host/lib/transport/super_recv_packet_handler.hpp b/host/lib/transport/super_recv_packet_handler.hpp
index 80ad17b6c..15bd78242 100644
--- a/host/lib/transport/super_recv_packet_handler.hpp
+++ b/host/lib/transport/super_recv_packet_handler.hpp
@@ -30,6 +30,7 @@
#include <uhd/transport/vrt_if_packet.hpp>
#include <uhd/transport/zero_copy.hpp>
#include <boost/thread/mutex.hpp>
+#include <boost/dynamic_bitset.hpp>
#include <boost/foreach.hpp>
#include <boost/function.hpp>
#include <boost/format.hpp>
@@ -51,61 +52,6 @@ typedef boost::function<void(void)> handle_overflow_type;
static inline void handle_overflow_nop(void){}
/***********************************************************************
- * Alignment indexes class:
- * - Access an integer set with very quick operations.
- **********************************************************************/
-class alignment_indexes{
-public:
- typedef boost::uint16_t index_type; //16 buffers
-
- alignment_indexes(void):
- _indexes(0),
- _sizes(256, 0),
- _fronts(256, ~0)
- {
- //fill the O(1) look up tables for a single byte
- for (size_t i = 0; i < 256; i++){
- for (size_t j = 0; j < 8; j++){
- if (i & (1 << j)){
- _sizes[i]++;
- _fronts[i] = j;
- }
- }
- }
- }
-
- UHD_INLINE void reset(size_t len){_indexes = (1 << len) - 1;}
-
- UHD_INLINE size_t front(void){
- //check one byte per iteration
- for (size_t i = 0; i < sizeof(_indexes)*8; i+=8){
- size_t front = _fronts[(_indexes >> i) & 0xff];
- if (front != size_t(~0)) return front + i;
- }
- if (empty()) throw uhd::runtime_error("cannot call front() when empty");
- UHD_THROW_INVALID_CODE_PATH();
- }
-
- UHD_INLINE void remove(size_t index){_indexes &= ~(1 << index);}
-
- UHD_INLINE bool empty(void){return _indexes == 0;}
-
- UHD_INLINE size_t size(void){
- size_t size = 0;
- //check one byte per iteration
- for (size_t i = 0; i < sizeof(_indexes)*8; i+=8){
- size += _sizes[(_indexes >> i) & 0xff];
- }
- return size;
- }
-
-private:
- index_type _indexes;
- std::vector<size_t> _sizes;
- std::vector<size_t> _fronts;
-};
-
-/***********************************************************************
* Super receive packet handler
*
* A receive packet handler represents a group of channels.
@@ -126,9 +72,9 @@ public:
_queue_error_for_next_call(false),
_buffers_infos_index(0)
{
- UHD_ASSERT_THROW(size <= sizeof(alignment_indexes::index_type)*8);
this->resize(size);
set_alignment_failure_threshold(1000);
+ this->set_scale_factor(1/32767.);
}
//! Resize the number of transport channels
@@ -208,6 +154,11 @@ public:
return boost::mutex::scoped_lock(_mutex);
}
+ //! Set the scale factor used in float conversion
+ void set_scale_factor(const double scale_factor){
+ _scale_factor = scale_factor;
+ }
+
/*******************************************************************
* Receive:
* The entry point for the fast-path receive calls.
@@ -293,6 +244,7 @@ private:
std::vector<void *> _io_buffs; //used in conversion
size_t _bytes_per_item; //used in conversion
std::vector<uhd::convert::function_type> _converters; //used in conversion
+ double _scale_factor;
//! information stored for a received buffer
struct per_buffer_info_type{
@@ -307,13 +259,12 @@ private:
struct buffers_info_type : std::vector<per_buffer_info_type> {
buffers_info_type(const size_t size):
std::vector<per_buffer_info_type>(size),
+ indexes_todo(size, true),
alignment_time_valid(false),
data_bytes_to_copy(0),
fragment_offset_in_samps(0)
- {
- indexes_to_do.reset(size);
- }
- alignment_indexes indexes_to_do; //used in alignment logic
+ {/* NOP */}
+ boost::dynamic_bitset<> indexes_todo; //used in alignment logic
time_spec_t alignment_time; //used in alignment logic
bool alignment_time_valid; //used in alignment logic
size_t data_bytes_to_copy; //keeps track of state
@@ -369,34 +320,30 @@ private:
info.time = time_spec_t(time_t(info.ifpi.tsi), size_t(info.ifpi.tsf), _tick_rate); //assumes has_tsi and has_tsf are true
info.copy_buff = reinterpret_cast<const char *>(info.vrt_hdr + info.ifpi.num_header_words32);
- //store the packet count for the next iteration
- #ifndef SRPH_DONT_CHECK_SEQUENCE
- const size_t expected_packet_count = _props[index].packet_count;
- _props[index].packet_count = (info.ifpi.packet_count + 1)%16;
- #endif
-
//--------------------------------------------------------------
//-- Determine return conditions:
//-- The order of these checks is HOLY.
//--------------------------------------------------------------
- //1) check for out of order timestamps
- if (info.ifpi.has_tsi and info.ifpi.has_tsf and prev_buffer_info[index].time > info.time){
- return PACKET_TIMESTAMP_ERROR;
- }
-
- //2) check for inline IF message packets
+ //1) check for inline IF message packets
if (info.ifpi.packet_type != vrt::if_packet_info_t::PACKET_TYPE_DATA){
return PACKET_INLINE_MESSAGE;
}
- //3) check for sequence errors
+ //2) check for sequence errors
#ifndef SRPH_DONT_CHECK_SEQUENCE
+ const size_t expected_packet_count = _props[index].packet_count;
+ _props[index].packet_count = (info.ifpi.packet_count + 1)%16;
if (expected_packet_count != info.ifpi.packet_count){
return PACKET_SEQUENCE_ERROR;
}
#endif
+ //3) check for out of order timestamps
+ if (info.ifpi.has_tsi and info.ifpi.has_tsf and prev_buffer_info[index].time > info.time){
+ return PACKET_TIMESTAMP_ERROR;
+ }
+
//4) otherwise the packet is normal!
return PACKET_IF_DATA;
}
@@ -414,15 +361,15 @@ private:
if (not info.alignment_time_valid or info[index].time > info.alignment_time){
info.alignment_time_valid = true;
info.alignment_time = info[index].time;
- info.indexes_to_do.reset(this->size());
- info.indexes_to_do.remove(index);
+ info.indexes_todo.set();
+ info.indexes_todo.reset(index);
info.data_bytes_to_copy = info[index].ifpi.num_payload_words32*sizeof(boost::uint32_t);
}
//if the sequence id matches:
// remove this index from the list and continue
else if (info[index].time == info.alignment_time){
- info.indexes_to_do.remove(index);
+ info.indexes_todo.reset(index);
}
//if the sequence id is older:
@@ -448,10 +395,10 @@ private:
// - Handle the packet type yielded by the receive.
// - Check the timestamps for alignment conditions.
size_t iterations = 0;
- while (not curr_info.indexes_to_do.empty()){
+ while (curr_info.indexes_todo.any()){
//get the index to process for this iteration
- const size_t index = curr_info.indexes_to_do.front();
+ const size_t index = curr_info.indexes_todo.find_first();
packet_type packet;
//receive a single packet from the transport
@@ -502,8 +449,10 @@ private:
curr_info.metadata.start_of_burst = false;
curr_info.metadata.end_of_burst = false;
curr_info.metadata.error_code = rx_metadata_t::error_code_t(get_context_code(next_info[index].vrt_hdr, next_info[index].ifpi));
- if (curr_info.metadata.error_code == rx_metadata_t::ERROR_CODE_OVERFLOW) _props[index].handle_overflow();
- UHD_MSG(fastpath) << "O";
+ if (curr_info.metadata.error_code == rx_metadata_t::ERROR_CODE_OVERFLOW){
+ _props[index].handle_overflow();
+ UHD_MSG(fastpath) << "O";
+ }
return;
case PACKET_TIMEOUT_ERROR:
@@ -589,7 +538,7 @@ private:
//reset current buffer info members for reuse
get_curr_buffer_info().fragment_offset_in_samps = 0;
get_curr_buffer_info().alignment_time_valid = false;
- get_curr_buffer_info().indexes_to_do.reset(this->size());
+ get_curr_buffer_info().indexes_todo.set();
//perform receive with alignment logic
get_aligned_buffs(timeout);
@@ -616,7 +565,7 @@ private:
}
//copy-convert the samples from the recv buffer
- _converters[io_type.tid](buff_info.copy_buff, _io_buffs, nsamps_to_copy_per_io_buff, 1/32767.);
+ _converters[io_type.tid](buff_info.copy_buff, _io_buffs, nsamps_to_copy_per_io_buff, _scale_factor);
//update the rx copy buffer to reflect the bytes copied
buff_info.copy_buff += bytes_to_copy;
diff --git a/host/lib/transport/super_send_packet_handler.hpp b/host/lib/transport/super_send_packet_handler.hpp
index 8ebc264ef..d5d9e6fe3 100644
--- a/host/lib/transport/super_send_packet_handler.hpp
+++ b/host/lib/transport/super_send_packet_handler.hpp
@@ -58,6 +58,7 @@ public:
_next_packet_seq(0)
{
this->resize(size);
+ this->set_scale_factor(32767.);
}
//! Resize the number of transport channels
@@ -132,6 +133,11 @@ public:
return boost::mutex::scoped_lock(_mutex);
}
+ //! Set the scale factor used in float conversion
+ void set_scale_factor(const double scale_factor){
+ _scale_factor = scale_factor;
+ }
+
/*******************************************************************
* Send:
* The entry point for the fast-path send calls.
@@ -238,11 +244,12 @@ private:
size_t _max_samples_per_packet;
std::vector<const void *> _zero_buffs;
size_t _next_packet_seq;
+ double _scale_factor;
/*******************************************************************
* Send a single packet:
******************************************************************/
- size_t send_one_packet(
+ UHD_INLINE size_t send_one_packet(
const uhd::device::send_buffs_type &buffs,
const size_t nsamps_per_buff,
vrt::if_packet_info_t &if_packet_info,
@@ -270,7 +277,7 @@ private:
otw_mem += if_packet_info.num_header_words32;
//copy-convert the samples into the send buffer
- _converters[io_type.tid](_io_buffs, otw_mem, nsamps_per_buff, 32767.);
+ _converters[io_type.tid](_io_buffs, otw_mem, nsamps_per_buff, _scale_factor);
//commit the samples to the zero-copy interface
size_t num_bytes_total = (_header_offset_words32+if_packet_info.num_packet_words32)*sizeof(boost::uint32_t);
diff --git a/host/lib/usrp/CMakeLists.txt b/host/lib/usrp/CMakeLists.txt
index 80f4bf45e..8ae379f73 100644
--- a/host/lib/usrp/CMakeLists.txt
+++ b/host/lib/usrp/CMakeLists.txt
@@ -24,18 +24,16 @@ LIBUHD_APPEND_SOURCES(
${CMAKE_CURRENT_SOURCE_DIR}/dboard_id.cpp
${CMAKE_CURRENT_SOURCE_DIR}/dboard_iface.cpp
${CMAKE_CURRENT_SOURCE_DIR}/dboard_manager.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/dsp_utils.cpp
${CMAKE_CURRENT_SOURCE_DIR}/gps_ctrl.cpp
${CMAKE_CURRENT_SOURCE_DIR}/mboard_eeprom.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/misc_utils.cpp
${CMAKE_CURRENT_SOURCE_DIR}/multi_usrp.cpp
${CMAKE_CURRENT_SOURCE_DIR}/subdev_spec.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/tune_helper.cpp
)
+INCLUDE_SUBDIRECTORY(cores)
INCLUDE_SUBDIRECTORY(dboard)
-INCLUDE_SUBDIRECTORY(fx2)
+INCLUDE_SUBDIRECTORY(common)
INCLUDE_SUBDIRECTORY(usrp1)
INCLUDE_SUBDIRECTORY(usrp2)
INCLUDE_SUBDIRECTORY(b100)
-INCLUDE_SUBDIRECTORY(usrp_e100)
+INCLUDE_SUBDIRECTORY(e100)
diff --git a/host/lib/usrp/b100/CMakeLists.txt b/host/lib/usrp/b100/CMakeLists.txt
index e1618a49c..1237f52d1 100644
--- a/host/lib/usrp/b100/CMakeLists.txt
+++ b/host/lib/usrp/b100/CMakeLists.txt
@@ -1,5 +1,5 @@
#
-# Copyright 2010-2011 Ettus Research LLC
+# Copyright 2011 Ettus Research LLC
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -26,22 +26,11 @@ LIBUHD_REGISTER_COMPONENT("B100" ENABLE_B100 ON "ENABLE_LIBUHD;ENABLE_USB" OFF)
IF(ENABLE_B100)
LIBUHD_APPEND_SOURCES(
+ ${CMAKE_CURRENT_SOURCE_DIR}/b100_ctrl.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/b100_impl.cpp
${CMAKE_CURRENT_SOURCE_DIR}/clock_ctrl.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/clock_ctrl.hpp
${CMAKE_CURRENT_SOURCE_DIR}/codec_ctrl.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/codec_ctrl.hpp
- ${CMAKE_CURRENT_SOURCE_DIR}/codec_impl.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/ctrl_packet.hpp
- ${CMAKE_CURRENT_SOURCE_DIR}/dboard_impl.cpp
${CMAKE_CURRENT_SOURCE_DIR}/dboard_iface.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/dsp_impl.cpp
${CMAKE_CURRENT_SOURCE_DIR}/io_impl.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/mboard_impl.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/b100_ctrl.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/b100_ctrl.hpp
- ${CMAKE_CURRENT_SOURCE_DIR}/b100_iface.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/b100_iface.hpp
- ${CMAKE_CURRENT_SOURCE_DIR}/b100_impl.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/b100_impl.hpp
)
ENDIF(ENABLE_B100)
diff --git a/host/lib/usrp/b100/b100_ctrl.cpp b/host/lib/usrp/b100/b100_ctrl.cpp
index 40b6435ac..e08b47ce4 100644
--- a/host/lib/usrp/b100/b100_ctrl.cpp
+++ b/host/lib/usrp/b100/b100_ctrl.cpp
@@ -1,5 +1,5 @@
//
-// Copyright 2010 Ettus Research LLC
+// Copyright 2011 Ettus Research LLC
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -15,18 +15,19 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
-#include "../../transport/super_recv_packet_handler.hpp"
#include "b100_ctrl.hpp"
-#include "b100_impl.hpp"
+#include <uhd/transport/bounded_buffer.hpp>
#include <uhd/transport/usb_zero_copy.hpp>
#include <uhd/transport/zero_copy.hpp>
#include <uhd/transport/vrt_if_packet.hpp>
#include <uhd/utils/thread_priority.hpp>
#include <uhd/utils/msg.hpp>
+#include <uhd/utils/tasks.hpp>
#include <uhd/types/metadata.hpp>
#include <uhd/types/serial.hpp>
#include "ctrl_packet.hpp"
-#include <boost/thread.hpp>
+#include <boost/thread/thread.hpp>
+#include <boost/bind.hpp>
#include <uhd/exception.hpp>
using namespace uhd::transport;
@@ -36,39 +37,67 @@ bool b100_ctrl_debug = false;
class b100_ctrl_impl : public b100_ctrl {
public:
- b100_ctrl_impl(uhd::transport::usb_zero_copy::sptr ctrl_transport) :
+ b100_ctrl_impl(uhd::transport::zero_copy_if::sptr ctrl_transport):
sync_ctrl_fifo(2),
- async_msg_fifo(100),
_ctrl_transport(ctrl_transport),
_seq(0)
{
- boost::barrier spawn_barrier(2);
- viking_marauders.create_thread(boost::bind(&b100_ctrl_impl::viking_marauder_loop, this, boost::ref(spawn_barrier)));
- spawn_barrier.wait();
+ viking_marauder = task::make(boost::bind(&b100_ctrl_impl::viking_marauder_loop, this));
}
-
+
int write(boost::uint32_t addr, const ctrl_data_t &data);
ctrl_data_t read(boost::uint32_t addr, size_t len);
-
- ~b100_ctrl_impl(void) {
- viking_marauders.interrupt_all();
- viking_marauders.join_all();
- }
-
+
bool get_ctrl_data(ctrl_data_t &pkt_data, double timeout);
- bool recv_async_msg(uhd::async_metadata_t &async_metadata, double timeout);
-
+
+ void poke32(wb_addr_type addr, boost::uint32_t data){
+ boost::mutex::scoped_lock lock(_ctrl_mutex);
+
+ ctrl_data_t words(2);
+ words[0] = data & 0x0000FFFF;
+ words[1] = data >> 16;
+ this->write(addr, words);
+ }
+
+ boost::uint32_t peek32(wb_addr_type addr){
+ boost::mutex::scoped_lock lock(_ctrl_mutex);
+
+ ctrl_data_t words = this->read(addr, 2);
+ return boost::uint32_t((boost::uint32_t(words[1]) << 16) | words[0]);
+ }
+
+ void poke16(wb_addr_type addr, boost::uint16_t data){
+ boost::mutex::scoped_lock lock(_ctrl_mutex);
+
+ ctrl_data_t words(1);
+ words[0] = data;
+ this->write(addr, words);
+ }
+
+ boost::uint16_t peek16(wb_addr_type addr){
+ boost::mutex::scoped_lock lock(_ctrl_mutex);
+
+ ctrl_data_t words = this->read(addr, 1);
+ return boost::uint16_t(words[0]);
+ }
+
+ void set_async_cb(const async_cb_type &async_cb){
+ boost::mutex::scoped_lock lock(_async_mutex);
+ _async_cb = async_cb;
+ }
+
private:
int send_pkt(boost::uint16_t *cmd);
-
+
//änd hërë wë gö ä-Vïkïng för äsynchronous control packets
- void viking_marauder_loop(boost::barrier &);
+ void viking_marauder_loop(void);
bounded_buffer<ctrl_data_t> sync_ctrl_fifo;
- bounded_buffer<async_metadata_t> async_msg_fifo;
- boost::thread_group viking_marauders;
-
- uhd::transport::usb_zero_copy::sptr _ctrl_transport;
+ async_cb_type _async_cb;
+ task::sptr viking_marauder;
+
+ uhd::transport::zero_copy_if::sptr _ctrl_transport;
boost::uint8_t _seq;
+ boost::mutex _ctrl_mutex, _async_mutex;
};
/***********************************************************************
@@ -86,7 +115,7 @@ void pack_ctrl_pkt(boost::uint16_t *pkt_buff,
pkt_buff[1] = pkt.pkt_meta.len;
pkt_buff[2] = (pkt.pkt_meta.addr & 0x00000FFF);
pkt_buff[3] = 0x0000; //address high bits always 0 on this device
-
+
for(size_t i = 0; i < pkt.data.size(); i++) {
pkt_buff[4+i] = pkt.data[i];
}
@@ -99,7 +128,7 @@ void unpack_ctrl_pkt(const boost::uint16_t *pkt_buff,
pkt.pkt_meta.len = pkt_buff[1];
pkt.pkt_meta.callbacks = 0; //callbacks aren't implemented yet
pkt.pkt_meta.addr = pkt_buff[2] | boost::uint32_t(pkt_buff[3] << 16);
-
+
//let's check this so we don't go pushing 64K of crap onto the pkt
if(pkt.pkt_meta.len > CTRL_PACKET_DATA_LENGTH) {
throw uhd::runtime_error("Received control packet too long");
@@ -113,7 +142,7 @@ int b100_ctrl_impl::send_pkt(boost::uint16_t *cmd) {
if(!sbuf.get()) {
throw uhd::runtime_error("Control channel send error");
}
-
+
//FIXME there's a better way to do this
for(size_t i = 0; i < (CTRL_PACKET_LENGTH / sizeof(boost::uint16_t)); i++) {
sbuf->cast<boost::uint16_t *>()[i] = cmd[i];
@@ -132,7 +161,7 @@ int b100_ctrl_impl::write(boost::uint32_t addr, const ctrl_data_t &data) {
pkt.pkt_meta.len = pkt.data.size();
pkt.pkt_meta.addr = addr;
boost::uint16_t pkt_buff[CTRL_PACKET_LENGTH / sizeof(boost::uint16_t)];
-
+
pack_ctrl_pkt(pkt_buff, pkt);
size_t result = send_pkt(pkt_buff);
return result;
@@ -149,11 +178,18 @@ ctrl_data_t b100_ctrl_impl::read(boost::uint32_t addr, size_t len) {
pkt.pkt_meta.addr = addr;
boost::uint16_t pkt_buff[CTRL_PACKET_LENGTH / sizeof(boost::uint16_t)];
+ //flush anything that might be in the queue
+ while (get_ctrl_data(pkt.data, 0.0)){
+ UHD_MSG(error) << "B100: control read found unexpected packet." << std::endl;
+ }
+
pack_ctrl_pkt(pkt_buff, pkt);
send_pkt(pkt_buff);
-
- //loop around waiting for the response to appear
- while(!get_ctrl_data(pkt.data, 0.05));
+
+ //block with timeout waiting for the response to appear
+ if (not get_ctrl_data(pkt.data, 0.1)) throw uhd::runtime_error(
+ "B100: timeout waiting for control response packet."
+ );
return pkt.data;
}
@@ -165,61 +201,40 @@ ctrl_data_t b100_ctrl_impl::read(boost::uint32_t addr, size_t len) {
* never have more than 1 message in it, since it's expected that we'll
* wait for a control operation to finish before starting another one.
**********************************************************************/
-void b100_ctrl_impl::viking_marauder_loop(boost::barrier &spawn_barrier) {
- spawn_barrier.wait();
+void b100_ctrl_impl::viking_marauder_loop(void){
set_thread_priority_safe();
-
+
while (not boost::this_thread::interruption_requested()){
- managed_recv_buffer::sptr rbuf = _ctrl_transport->get_recv_buff();
- if(!rbuf.get()) continue; //that's ok, there are plenty of villages to pillage!
+ managed_recv_buffer::sptr rbuf = _ctrl_transport->get_recv_buff(1.0);
+ if(rbuf.get() == NULL) continue; //that's ok, there are plenty of villages to pillage!
const boost::uint16_t *pkt_buf = rbuf->cast<const boost::uint16_t *>();
-
+
if(pkt_buf[0] >> 8 == CTRL_PACKET_HEADER_MAGIC) {
//so it's got a control packet header, let's parse it.
ctrl_pkt_t pkt;
unpack_ctrl_pkt(pkt_buf, pkt);
-
+
if(pkt.pkt_meta.seq != boost::uint8_t(_seq - 1)) {
- throw uhd::runtime_error("Sequence error on control channel");
+ UHD_MSG(error)
+ << "Sequence error on control channel." << std::endl
+ << "Exiting control loop." << std::endl
+ ;
+ return;
}
if(pkt.pkt_meta.len > (CTRL_PACKET_LENGTH - CTRL_PACKET_HEADER_LENGTH)) {
- throw uhd::runtime_error("Control channel packet length too long");
+ UHD_MSG(error)
+ << "Control channel packet length too long" << std::endl
+ << "Exiting control loop." << std::endl
+ ;
+ return;
}
-
+
//push it onto the queue
- sync_ctrl_fifo.push_with_wait(pkt.data);
- } else { //it's an async status pkt
- //extract the vrt header packet info
- vrt::if_packet_info_t if_packet_info;
- if_packet_info.num_packet_words32 = rbuf->size()/sizeof(boost::uint32_t);
- const boost::uint32_t *vrt_hdr = rbuf->cast<const boost::uint32_t *>();
- vrt::if_hdr_unpack_le(vrt_hdr, if_packet_info);
-
- if( if_packet_info.sid == 0
- 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 = 0;
- 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), 64e6 //FIXME get from clock_ctrl
- );
- metadata.event_code = async_metadata_t::event_code_t(sph::get_context_code(vrt_hdr, if_packet_info));
- //print the famous U, and push the metadata into the message queue
- if (metadata.event_code &
- ( async_metadata_t::EVENT_CODE_UNDERFLOW
- | async_metadata_t::EVENT_CODE_UNDERFLOW_IN_PACKET) )
- UHD_MSG(fastpath) << "U";
-
- if (metadata.event_code &
- ( async_metadata_t::EVENT_CODE_SEQ_ERROR
- | async_metadata_t::EVENT_CODE_SEQ_ERROR_IN_BURST) )
- UHD_MSG(fastpath) << "S";
-
- async_msg_fifo.push_with_pop_on_full(metadata);
- continue;
- }
- throw uhd::runtime_error("Control: unknown async response");
+ sync_ctrl_fifo.push_with_pop_on_full(pkt.data);
+ }
+ else{ //otherwise let the async callback handle it
+ boost::mutex::scoped_lock lock(_async_mutex);
+ if (not _async_cb.empty()) _async_cb(rbuf);
}
}
}
@@ -229,14 +244,9 @@ bool b100_ctrl_impl::get_ctrl_data(ctrl_data_t &pkt_data, double timeout){
return sync_ctrl_fifo.pop_with_timed_wait(pkt_data, timeout);
}
-bool b100_ctrl_impl::recv_async_msg(uhd::async_metadata_t &async_metadata, double timeout) {
- boost::this_thread::disable_interruption di; //disable because the wait can throw
- return async_msg_fifo.pop_with_timed_wait(async_metadata, timeout);
-}
-
/***********************************************************************
* Public make function for b100_ctrl interface
**********************************************************************/
-b100_ctrl::sptr b100_ctrl::make(uhd::transport::usb_zero_copy::sptr ctrl_transport){
+b100_ctrl::sptr b100_ctrl::make(uhd::transport::zero_copy_if::sptr ctrl_transport){
return sptr(new b100_ctrl_impl(ctrl_transport));
}
diff --git a/host/lib/usrp/b100/b100_ctrl.hpp b/host/lib/usrp/b100/b100_ctrl.hpp
index ae706dbb4..74884d525 100644
--- a/host/lib/usrp/b100/b100_ctrl.hpp
+++ b/host/lib/usrp/b100/b100_ctrl.hpp
@@ -1,5 +1,5 @@
//
-// Copyright 2010 Ettus Research LLC
+// Copyright 2011 Ettus Research LLC
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -18,25 +18,28 @@
#ifndef INCLUDED_B100_CTRL_HPP
#define INCLUDED_B100_CTRL_HPP
-#include <uhd/transport/bounded_buffer.hpp>
+#include "wb_iface.hpp"
#include <uhd/transport/usb_zero_copy.hpp>
-#include <uhd/types/metadata.hpp>
#include <uhd/types/serial.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/utility.hpp>
#include "ctrl_packet.hpp"
-#include <boost/thread.hpp>
+#include <boost/function.hpp>
-class b100_ctrl : boost::noncopyable{
+class b100_ctrl : boost::noncopyable, public wb_iface{
public:
typedef boost::shared_ptr<b100_ctrl> sptr;
+ typedef boost::function<void(uhd::transport::managed_recv_buffer::sptr)> async_cb_type;
/*!
* Make a USRP control object from a data transport
* \param ctrl_transport a USB data transport
* \return a new b100 control object
*/
- static sptr make(uhd::transport::usb_zero_copy::sptr ctrl_transport);
+ static sptr make(uhd::transport::zero_copy_if::sptr ctrl_transport);
+
+ //! set an async callback for messages
+ virtual void set_async_cb(const async_cb_type &async_cb) = 0;
/*!
* Write a byte vector to an FPGA register
@@ -61,9 +64,7 @@ public:
* \return true if it got something
*/
virtual bool get_ctrl_data(ctrl_data_t &pkt_data, double timeout) = 0;
-
- virtual bool recv_async_msg(uhd::async_metadata_t &async_metadata, double timeout) = 0;
-
+
};
#endif /* INCLUDED_B100_CTRL_HPP */
diff --git a/host/lib/usrp/b100/b100_iface.cpp b/host/lib/usrp/b100/b100_iface.cpp
deleted file mode 100644
index 17ea2e6ad..000000000
--- a/host/lib/usrp/b100/b100_iface.cpp
+++ /dev/null
@@ -1,336 +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 "b100_iface.hpp"
-#include "usrp_commands.h"
-#include <uhd/exception.hpp>
-#include <uhd/utils/byteswap.hpp>
-#include <uhd/utils/safe_call.hpp>
-#include <uhd/utils/msg.hpp>
-#include <boost/format.hpp>
-#include <iomanip>
-#include <iostream>
-
-//FOR TESTING ONLY
-#include "b100_regs.hpp"
-#include <boost/thread/thread.hpp>
-#include "usrp_i2c_addr.h"
-
-using namespace uhd;
-using namespace uhd::usrp;
-using namespace uhd::transport;
-
-/***********************************************************************
- * Constants
- **********************************************************************/
-static const bool iface_debug = true;
-static const boost::uint16_t USRP_B_FW_COMPAT_NUM = 0x02;
-static const boost::uint16_t USRP_B_FPGA_COMPAT_NUM = 0x03;
-
-/***********************************************************************
- * I2C + FX2 implementation wrapper
- **********************************************************************/
-class b100_i2c_fx2_iface : public i2c_iface{
-public:
- b100_i2c_fx2_iface(uhd::usrp::fx2_ctrl::sptr fx2_ctrl){
- _fx2_ctrl = fx2_ctrl;
- }
-
- void write_i2c(boost::uint8_t addr, const byte_vector_t &bytes)
- {
- UHD_ASSERT_THROW(bytes.size() < max_i2c_data_bytes);
-
- unsigned char buff[max_i2c_data_bytes];
- std::copy(bytes.begin(), bytes.end(), buff);
-
- int ret = _fx2_ctrl->usrp_i2c_write(addr & 0xff,
- buff,
- bytes.size());
-
- if (iface_debug && (ret < 0))
- uhd::runtime_error("USRP: failed i2c write");
- }
-
- byte_vector_t read_i2c(boost::uint8_t addr, size_t num_bytes)
- {
- UHD_ASSERT_THROW(num_bytes < max_i2c_data_bytes);
-
- unsigned char buff[max_i2c_data_bytes];
- int ret = _fx2_ctrl->usrp_i2c_read(addr & 0xff,
- buff,
- num_bytes);
-
- if (iface_debug && ((ret < 0) || (unsigned)ret < (num_bytes)))
- uhd::runtime_error("USRP: failed i2c read");
-
- byte_vector_t out_bytes;
- for (size_t i = 0; i < num_bytes; i++)
- out_bytes.push_back(buff[i]);
-
- return out_bytes;
- }
-
-private:
- static const size_t max_i2c_data_bytes = 64;
- uhd::usrp::fx2_ctrl::sptr _fx2_ctrl;
-};
-
-/***********************************************************************
- * USRP-E100 interface implementation
- **********************************************************************/
-class b100_iface_impl : public b100_iface{
-public:
- /*******************************************************************
- * Structors
- ******************************************************************/
- b100_iface_impl(uhd::usrp::fx2_ctrl::sptr fx2_ctrl,
- b100_ctrl::sptr fpga_ctrl) :
- _fx2_i2c_iface(fx2_ctrl),
- _fx2_ctrl(fx2_ctrl),
- _fpga_ctrl(fpga_ctrl)
- {
- this->check_fw_compat();
- if (fpga_ctrl.get() != NULL){
- enable_gpif(1);
- i2c_init();
- this->check_fpga_compat();
- }
- mb_eeprom = mboard_eeprom_t(get_fx2_i2c_iface(), mboard_eeprom_t::MAP_B000);
- }
-
- void check_fw_compat(void){
- unsigned char data[4]; //useless data buffer
- const boost::uint16_t fw_compat_num = _fx2_ctrl->usrp_control_read(
- VRQ_FW_COMPAT, 0, 0, data, sizeof(data)
- );
- if (fw_compat_num != USRP_B_FW_COMPAT_NUM){
- throw uhd::runtime_error(str(boost::format(
- "Expected firmware compatibility number 0x%x, but got 0x%x:\n"
- "The firmware build is not compatible with the host code build."
- ) % USRP_B_FW_COMPAT_NUM % fw_compat_num));
- }
- }
-
- void check_fpga_compat(void){
- const boost::uint16_t fpga_compat_num = this->peek16(B100_REG_MISC_COMPAT);
- if (fpga_compat_num != USRP_B_FPGA_COMPAT_NUM){
- throw uhd::runtime_error(str(boost::format(
- "Expected FPGA compatibility number 0x%x, but got 0x%x:\n"
- "The FPGA build is not compatible with the host code build."
- ) % USRP_B_FPGA_COMPAT_NUM % fpga_compat_num));
- }
- }
-
- ~b100_iface_impl(void)
- {
- /* NOP */
- }
-
- /*******************************************************************
- * Peek and Poke
- ******************************************************************/
-
- void poke(boost::uint32_t addr, const ctrl_data_t &data) {
- boost::mutex::scoped_lock lock(_ctrl_mutex);
- _fpga_ctrl->write(addr, data);
- }
-
- ctrl_data_t peek(boost::uint32_t addr, size_t len) {
- boost::mutex::scoped_lock lock(_ctrl_mutex);
- return _fpga_ctrl->read(addr, len);
- }
-
- void poke16(boost::uint32_t addr, boost::uint16_t value)
- {
- ctrl_data_t words(1);
- words[0] = value;
- poke(addr, words);
- }
-
- void poke32(boost::uint32_t addr, boost::uint32_t value)
- {
- //just a subset of poke() to maintain compatibility
- ctrl_data_t words(2);
- words[0] = value & 0x0000FFFF;
- words[1] = value >> 16;
- poke(addr, words);
- }
-
- boost::uint32_t peek32(boost::uint32_t addr)
- {
- ctrl_data_t words = peek(addr, 2);
- return boost::uint32_t((boost::uint32_t(words[1]) << 16) | words[0]);
- }
-
- boost::uint16_t peek16(boost::uint32_t addr)
- {
- ctrl_data_t words = peek(addr, 1);
- return boost::uint16_t(words[0]);
- }
-
- /*******************************************************************
- * I2C
- ******************************************************************/
- static const boost::uint32_t i2c_datarate = 400000;
- static const boost::uint32_t wishbone_clk = 64000000; //FIXME should go somewhere else
-
- void i2c_init(void) {
- //init I2C FPGA interface.
- poke16(B100_REG_I2C_CTRL, 0x0000);
- //set prescalers to operate at 400kHz: WB_CLK is 64MHz...
- boost::uint16_t prescaler = wishbone_clk / (i2c_datarate*5) - 1;
- poke16(B100_REG_I2C_PRESCALER_LO, prescaler & 0xFF);
- poke16(B100_REG_I2C_PRESCALER_HI, (prescaler >> 8) & 0xFF);
- poke16(B100_REG_I2C_CTRL, I2C_CTRL_EN); //enable I2C core
- }
-
- static const size_t max_i2c_data_bytes = 64;
-
- void i2c_wait_for_xfer(void)
- {
- while(this->peek16(B100_REG_I2C_CMD_STATUS) & I2C_ST_TIP)
- boost::this_thread::sleep(boost::posix_time::milliseconds(10));
- }
-
- bool wait_chk_ack(void) {
- i2c_wait_for_xfer();
- return (this->peek16(B100_REG_I2C_CMD_STATUS) & I2C_ST_RXACK) == 0;
- }
-
- void write_i2c(boost::uint8_t addr, const byte_vector_t &bytes)
- {
- poke16(B100_REG_I2C_DATA, (addr << 1) | 0); //addr and read bit (0)
- poke16(B100_REG_I2C_CMD_STATUS, I2C_CMD_WR | I2C_CMD_START | (bytes.size() == 0 ? I2C_CMD_STOP : 0));
-
- //wait for previous transfer to complete
- if(!wait_chk_ack()) {
- poke16(B100_REG_I2C_CMD_STATUS, I2C_CMD_STOP);
- return;
- }
-
- for(size_t i = 0; i < bytes.size(); i++) {
- poke16(B100_REG_I2C_DATA, bytes[i]);
- poke16(B100_REG_I2C_CMD_STATUS, I2C_CMD_WR | ((i == (bytes.size() - 1)) ? I2C_CMD_STOP : 0));
- if(!wait_chk_ack()) {
- poke16(B100_REG_I2C_CMD_STATUS, I2C_CMD_STOP);
- return;
- }
- }
- }
-
- byte_vector_t read_i2c(boost::uint8_t addr, size_t num_bytes)
- {
- byte_vector_t bytes;
- if(num_bytes == 0) return bytes;
-
- while (peek16(B100_REG_I2C_CMD_STATUS) & I2C_ST_BUSY);
-
- poke16(B100_REG_I2C_DATA, (addr << 1) | 1); //addr and read bit (1)
- poke16(B100_REG_I2C_CMD_STATUS, I2C_CMD_WR | I2C_CMD_START);
- //wait for previous transfer to complete
- if(!wait_chk_ack()) {
- poke16(B100_REG_I2C_CMD_STATUS, I2C_CMD_STOP);
- }
-
- for(; num_bytes > 0; num_bytes--) {
- poke16(B100_REG_I2C_CMD_STATUS, I2C_CMD_RD | ((num_bytes == 1) ? (I2C_CMD_STOP | I2C_CMD_NACK) : 0));
- i2c_wait_for_xfer();
- boost::uint8_t readback = peek16(B100_REG_I2C_DATA) & 0xFF;
- bytes.push_back(readback);
- }
- return bytes;
- }
-
- i2c_iface &get_fx2_i2c_iface(void){
- return _fx2_i2c_iface;
- }
-
- /*******************************************************************
- * SPI interface
- * Eventually this will be replaced with a control-channel system
- * to let the firmware do the actual write/readback cycles.
- * This keeps the bandwidth on the control channel down.
- ******************************************************************/
-
- void spi_wait(void) {
- while(peek32(B100_REG_SPI_CTRL) & SPI_CTRL_GO_BSY);
- }
-
- boost::uint32_t transact_spi(int which_slave,
- const spi_config_t &config,
- boost::uint32_t bits,
- size_t num_bits,
- bool readback)
- {
- UHD_ASSERT_THROW((num_bits <= 32) && !(num_bits % 8));
-
- int edge_flags = ((config.miso_edge==spi_config_t::EDGE_FALL) ? SPI_CTRL_RXNEG : 0) |
- ((config.mosi_edge==spi_config_t::EDGE_FALL) ? 0 : SPI_CTRL_TXNEG)
- ;
-
- boost::uint16_t ctrl = SPI_CTRL_ASS | (SPI_CTRL_CHAR_LEN_MASK & num_bits) | edge_flags;
-
- poke16(B100_REG_SPI_DIV, 0x0001); // = fpga_clk / 4
- poke32(B100_REG_SPI_SS, which_slave & 0xFFFF);
- poke32(B100_REG_SPI_TXRX0, bits);
- poke16(B100_REG_SPI_CTRL, ctrl);
-
- poke16(B100_REG_SPI_CTRL, ctrl | SPI_CTRL_GO_BSY);
- if(readback) {
- spi_wait();
- return peek32(B100_REG_SPI_TXRX0);
- }
- else {
- return 0;
- }
- }
-
- void reset_gpif(boost::uint16_t ep) {
- _fx2_ctrl->usrp_control_write(VRQ_RESET_GPIF, ep, ep, 0, 0);
- }
-
- void enable_gpif(bool en) {
- _fx2_ctrl->usrp_control_write(VRQ_ENABLE_GPIF, en ? 1 : 0, 0, 0, 0);
- }
-
- void clear_fpga_fifo(void) {
- _fx2_ctrl->usrp_control_write(VRQ_CLEAR_FPGA_FIFO, 0, 0, 0, 0);
- }
-
- void write_uart(boost::uint8_t, const std::string &) {
- throw uhd::not_implemented_error("Unhandled command write_uart()");
- }
-
- std::string read_uart(boost::uint8_t) {
- throw uhd::not_implemented_error("Unhandled command read_uart()");
- }
-
-private:
- b100_i2c_fx2_iface _fx2_i2c_iface;
- uhd::usrp::fx2_ctrl::sptr _fx2_ctrl;
- b100_ctrl::sptr _fpga_ctrl;
- boost::mutex _ctrl_mutex;
-};
-
-/***********************************************************************
- * Public Make Function
- **********************************************************************/
-b100_iface::sptr b100_iface::make(uhd::usrp::fx2_ctrl::sptr fx2_ctrl,
- b100_ctrl::sptr fpga_ctrl)
-{
- return b100_iface::sptr(new b100_iface_impl(fx2_ctrl, fpga_ctrl));
-}
diff --git a/host/lib/usrp/b100/b100_iface.hpp b/host/lib/usrp/b100/b100_iface.hpp
deleted file mode 100644
index 57ed6a45c..000000000
--- a/host/lib/usrp/b100/b100_iface.hpp
+++ /dev/null
@@ -1,73 +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_B100_IFACE_HPP
-#define INCLUDED_B100_IFACE_HPP
-
-#include <uhd/usrp/mboard_iface.hpp>
-#include <uhd/usrp/mboard_eeprom.hpp>
-#include <boost/shared_ptr.hpp>
-#include <boost/utility.hpp>
-#include <uhd/transport/usb_zero_copy.hpp>
-#include "../fx2/fx2_ctrl.hpp"
-#include "b100_ctrl.hpp"
-
-/*!
- * The usrp1 interface class:
- * Provides a set of functions to implementation layer.
- * Including spi, peek, poke, control...
- */
-class b100_iface : boost::noncopyable, public uhd::usrp::mboard_iface{
-public:
- typedef boost::shared_ptr<b100_iface> sptr;
-
- /*!
- * Make a new b100 interface with the control transport.
- * \param fx2_ctrl the usrp control object
- * \param fpga_ctrl the FPGA interface control object
- * \return a new usrp1 interface object
- */
- static sptr make(uhd::usrp::fx2_ctrl::sptr fx2_ctrl,
- b100_ctrl::sptr fpga_ctrl = b100_ctrl::sptr()
- );
-
- /*!
- * Reset the GPIF interface on the FX2
- * \param which endpoint to reset
- * \return
- */
- virtual void reset_gpif(boost::uint16_t ep) = 0;
-
- /*!
- * Clear the GPIF FIFOs on the FPGA
- * \return
- */
- virtual void clear_fpga_fifo(void) = 0;
-
- /*!
- * Enable/disable the GPIF interfaces on the FX2
- * \return
- */
- virtual void enable_gpif(bool en) = 0;
-
- //! Get access to the FX2 I2C interface
- virtual uhd::i2c_iface &get_fx2_i2c_iface(void) = 0;
-
- uhd::usrp::mboard_eeprom_t mb_eeprom;
-};
-
-#endif /* INCLUDED_USRP1_IFACE_HPP */
diff --git a/host/lib/usrp/b100/b100_impl.cpp b/host/lib/usrp/b100/b100_impl.cpp
index 7e733ddd9..2e2421ed3 100644
--- a/host/lib/usrp/b100/b100_impl.cpp
+++ b/host/lib/usrp/b100/b100_impl.cpp
@@ -1,5 +1,5 @@
//
-// Copyright 2010 Ettus Research LLC
+// Copyright 2011 Ettus Research LLC
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -18,11 +18,10 @@
#include "b100_impl.hpp"
#include "b100_ctrl.hpp"
#include "fpga_regs_standard.h"
-#include "usrp_spi_defs.h"
+#include "usrp_i2c_addr.h"
+#include "usrp_commands.h"
#include <uhd/transport/usb_control.hpp>
#include "ctrl_packet.hpp"
-#include <uhd/usrp/device_props.hpp>
-#include <uhd/usrp/mboard_props.hpp>
#include <uhd/utils/msg.hpp>
#include <uhd/exception.hpp>
#include <uhd/utils/static.hpp>
@@ -72,7 +71,7 @@ static device_addrs_t b100_find(const device_addr_t &hint)
//extract the firmware path for the b100
std::string b100_fw_image;
try{
- b100_fw_image = find_image_path(hint.get("fw", "usrp_b100_fw.ihx"));
+ b100_fw_image = find_image_path(hint.get("fw", B100_FW_FILE_NAME));
}
catch(...){
UHD_MSG(warning) << boost::format(
@@ -97,20 +96,19 @@ static device_addrs_t b100_find(const device_addr_t &hint)
BOOST_FOREACH(usb_device_handle::sptr handle, usb_device_handle::get_device_list(vid, pid)) {
device_addr_t new_addr;
new_addr["type"] = "b100";
+ new_addr["serial"] = handle->get_serial();
//Attempt to read the name from the EEPROM and perform filtering.
- //This operation can throw due to compatibility mismatch.
try{
usb_control::sptr control = usb_control::make(handle);
- b100_iface::sptr iface = b100_iface::make(fx2_ctrl::make(control));
- new_addr["name"] = iface->mb_eeprom["name"];
- new_addr["serial"] = handle->get_serial();
+ fx2_ctrl::sptr fx2_ctrl = fx2_ctrl::make(control);
+ const mboard_eeprom_t mb_eeprom = mboard_eeprom_t(*fx2_ctrl, mboard_eeprom_t::MAP_B000);
+ new_addr["name"] = mb_eeprom["name"];
}
catch(const uhd::exception &){
//set these values as empty string so the device may still be found
//and the filter's below can still operate on the discovered device
new_addr["name"] = "";
- new_addr["serial"] = "";
}
//this is a found b100 when the hint serial and name match or blank
@@ -129,10 +127,21 @@ static device_addrs_t b100_find(const device_addr_t &hint)
* Make
**********************************************************************/
static device::sptr b100_make(const device_addr_t &device_addr){
+ return device::sptr(new b100_impl(device_addr));
+}
+
+UHD_STATIC_BLOCK(register_b100_device){
+ device::register_device(&b100_find, &b100_make);
+}
+
+/***********************************************************************
+ * Structors
+ **********************************************************************/
+b100_impl::b100_impl(const device_addr_t &device_addr){
//extract the FPGA path for the B100
std::string b100_fpga_image = find_image_path(
- device_addr.has_key("fpga")? device_addr["fpga"] : "usrp_b100_fpga.bin"
+ device_addr.has_key("fpga")? device_addr["fpga"] : B100_FPGA_FILE_NAME
);
//try to match the given device address with something on the USB bus
@@ -151,8 +160,11 @@ static device::sptr b100_make(const device_addr_t &device_addr){
//create control objects and a data transport
usb_control::sptr fx2_transport = usb_control::make(handle);
- fx2_ctrl::sptr fx2_ctrl = fx2_ctrl::make(fx2_transport);
- fx2_ctrl->usrp_load_fpga(b100_fpga_image);
+ _fx2_ctrl = fx2_ctrl::make(fx2_transport);
+ this->check_fw_compat(); //check after making fx2
+ //-- setup clock after making fx2 and before loading fpga --//
+ _clock_ctrl = b100_clock_ctrl::make(_fx2_ctrl, device_addr.cast<double>("master_clock_rate", B100_DEFAULT_TICK_RATE));
+ _fx2_ctrl->usrp_load_fpga(b100_fpga_image);
device_addr_t data_xport_args;
data_xport_args["recv_frame_size"] = device_addr.get("recv_frame_size", "16384");
@@ -160,7 +172,7 @@ static device::sptr b100_make(const device_addr_t &device_addr){
data_xport_args["send_frame_size"] = device_addr.get("send_frame_size", "16384");
data_xport_args["num_send_frames"] = device_addr.get("num_send_frames", "16");
- usb_zero_copy::sptr data_transport = usb_zero_copy::make_wrapper(
+ _data_transport = usb_zero_copy::make_wrapper(
usb_zero_copy::make(
handle, // identifier
6, // IN endpoint
@@ -176,105 +188,280 @@ static device::sptr b100_make(const device_addr_t &device_addr){
ctrl_xport_args["send_frame_size"] = boost::lexical_cast<std::string>(CTRL_PACKET_LENGTH);
ctrl_xport_args["num_send_frames"] = "4";
- usb_zero_copy::sptr ctrl_transport = usb_zero_copy::make(
+ _ctrl_transport = usb_zero_copy::make(
handle,
8,
4,
ctrl_xport_args
);
- const double master_clock_rate = device_addr.cast<double>("master_clock_rate", 64e6);
-
-
- //create the b100 implementation guts
- return device::sptr(new b100_impl(data_transport, ctrl_transport, fx2_ctrl, master_clock_rate));
-}
-
-UHD_STATIC_BLOCK(register_b100_device){
- device::register_device(&b100_find, &b100_make);
-}
-
-/***********************************************************************
- * Structors
- **********************************************************************/
-b100_impl::b100_impl(uhd::transport::usb_zero_copy::sptr data_transport,
- uhd::transport::usb_zero_copy::sptr ctrl_transport,
- uhd::usrp::fx2_ctrl::sptr fx2_ctrl,
- const double master_clock_rate)
- : _data_transport(data_transport), _fx2_ctrl(fx2_ctrl)
-{
- //this is the handler object for FPGA control packets
- _fpga_ctrl = b100_ctrl::make(ctrl_transport);
-
- _iface = b100_iface::make(_fx2_ctrl, _fpga_ctrl);
-
- //create clock interface
- _clock_ctrl = b100_clock_ctrl::make(_iface, master_clock_rate);
-
- //create codec interface
- _codec_ctrl = b100_codec_ctrl::make(_iface);
+ ////////////////////////////////////////////////////////////////////
+ // Create controller objects
+ ////////////////////////////////////////////////////////////////////
+ _fpga_ctrl = b100_ctrl::make(_ctrl_transport);
+ this->enable_gpif(true); //TODO best place to put this?
+ this->check_fpga_compat(); //check after making control
+ _fpga_i2c_ctrl = i2c_core_100::make(_fpga_ctrl, B100_REG_SLAVE(3));
+ _fpga_spi_ctrl = spi_core_100::make(_fpga_ctrl, B100_REG_SLAVE(2));
+
+ ////////////////////////////////////////////////////////////////////
+ // Initialize the properties tree
+ ////////////////////////////////////////////////////////////////////
+ _tree = property_tree::make();
+ _tree->create<std::string>("/name").set("B-Series Device");
+ const property_tree::path_type mb_path = "/mboards/0";
+ _tree->create<std::string>(mb_path / "name").set("B100 (B-Hundo)");
+ _tree->create<std::string>(mb_path / "load_eeprom")
+ .subscribe(boost::bind(&fx2_ctrl::usrp_load_eeprom, _fx2_ctrl, _1));
+
+ ////////////////////////////////////////////////////////////////////
+ // setup the mboard eeprom
+ ////////////////////////////////////////////////////////////////////
+ const mboard_eeprom_t mb_eeprom(*_fx2_ctrl, mboard_eeprom_t::MAP_B000);
+ _tree->create<mboard_eeprom_t>(mb_path / "eeprom")
+ .set(mb_eeprom)
+ .subscribe(boost::bind(&b100_impl::set_mb_eeprom, this, _1));
+
+ ////////////////////////////////////////////////////////////////////
+ // create clock control objects
+ ////////////////////////////////////////////////////////////////////
+ //^^^ clock created up top, just reg props here... ^^^
+ _tree->create<double>(mb_path / "tick_rate")
+ .publish(boost::bind(&b100_clock_ctrl::get_fpga_clock_rate, _clock_ctrl))
+ .subscribe(boost::bind(&b100_impl::update_tick_rate, this, _1));
+
+ ////////////////////////////////////////////////////////////////////
+ // create codec control objects
+ ////////////////////////////////////////////////////////////////////
+ _codec_ctrl = b100_codec_ctrl::make(_fpga_spi_ctrl);
+ const property_tree::path_type rx_codec_path = mb_path / "rx_codecs/A";
+ const property_tree::path_type tx_codec_path = mb_path / "tx_codecs/A";
+ _tree->create<std::string>(rx_codec_path / "name").set("ad9522");
+ _tree->create<meta_range_t>(rx_codec_path / "gains/pga/range").set(b100_codec_ctrl::rx_pga_gain_range);
+ _tree->create<double>(rx_codec_path / "gains/pga/value")
+ .coerce(boost::bind(&b100_impl::update_rx_codec_gain, this, _1));
+ _tree->create<std::string>(tx_codec_path / "name").set("ad9522");
+ _tree->create<meta_range_t>(tx_codec_path / "gains/pga/range").set(b100_codec_ctrl::tx_pga_gain_range);
+ _tree->create<double>(tx_codec_path / "gains/pga/value")
+ .subscribe(boost::bind(&b100_codec_ctrl::set_tx_pga_gain, _codec_ctrl, _1))
+ .publish(boost::bind(&b100_codec_ctrl::get_tx_pga_gain, _codec_ctrl));
+
+ ////////////////////////////////////////////////////////////////////
+ // and do the misc mboard sensors
+ ////////////////////////////////////////////////////////////////////
+ //none for now...
+ _tree->create<int>(mb_path / "sensors"); //phony property so this dir exists
+
+ ////////////////////////////////////////////////////////////////////
+ // create frontend control objects
+ ////////////////////////////////////////////////////////////////////
+ _rx_fe = rx_frontend_core_200::make(_fpga_ctrl, B100_REG_SR_ADDR(B100_SR_RX_FRONT));
+ _tx_fe = tx_frontend_core_200::make(_fpga_ctrl, B100_REG_SR_ADDR(B100_SR_TX_FRONT));
+ //TODO lots of properties to expose here for frontends
+ _tree->create<subdev_spec_t>(mb_path / "rx_subdev_spec")
+ .subscribe(boost::bind(&b100_impl::update_rx_subdev_spec, this, _1));
+ _tree->create<subdev_spec_t>(mb_path / "tx_subdev_spec")
+ .subscribe(boost::bind(&b100_impl::update_tx_subdev_spec, this, _1));
+
+ ////////////////////////////////////////////////////////////////////
+ // create rx dsp control objects
+ ////////////////////////////////////////////////////////////////////
+ _rx_dsps.push_back(rx_dsp_core_200::make(
+ _fpga_ctrl, B100_REG_SR_ADDR(B100_SR_RX_DSP0), B100_REG_SR_ADDR(B100_SR_RX_CTRL0), B100_RX_SID_BASE + 0
+ ));
+ _rx_dsps.push_back(rx_dsp_core_200::make(
+ _fpga_ctrl, B100_REG_SR_ADDR(B100_SR_RX_DSP1), B100_REG_SR_ADDR(B100_SR_RX_CTRL1), B100_RX_SID_BASE + 1
+ ));
+ for (size_t dspno = 0; dspno < _rx_dsps.size(); dspno++){
+ _rx_dsps[dspno]->set_link_rate(B100_LINK_RATE_BPS);
+ _tree->access<double>(mb_path / "tick_rate")
+ .subscribe(boost::bind(&rx_dsp_core_200::set_tick_rate, _rx_dsps[dspno], _1));
+ property_tree::path_type rx_dsp_path = mb_path / str(boost::format("rx_dsps/%u") % dspno);
+ _tree->create<double>(rx_dsp_path / "rate/value")
+ .coerce(boost::bind(&rx_dsp_core_200::set_host_rate, _rx_dsps[dspno], _1))
+ .subscribe(boost::bind(&b100_impl::update_rx_samp_rate, this, _1));
+ _tree->create<double>(rx_dsp_path / "freq/value")
+ .coerce(boost::bind(&rx_dsp_core_200::set_freq, _rx_dsps[dspno], _1));
+ _tree->create<meta_range_t>(rx_dsp_path / "freq/range")
+ .publish(boost::bind(&rx_dsp_core_200::get_freq_range, _rx_dsps[dspno]));
+ _tree->create<stream_cmd_t>(rx_dsp_path / "stream_cmd")
+ .subscribe(boost::bind(&rx_dsp_core_200::issue_stream_command, _rx_dsps[dspno], _1));
+ }
- //initialize the codecs
- codec_init();
+ ////////////////////////////////////////////////////////////////////
+ // create tx dsp control objects
+ ////////////////////////////////////////////////////////////////////
+ _tx_dsp = tx_dsp_core_200::make(
+ _fpga_ctrl, B100_REG_SR_ADDR(B100_SR_TX_DSP), B100_REG_SR_ADDR(B100_SR_TX_CTRL), B100_TX_ASYNC_SID
+ );
+ _tx_dsp->set_link_rate(B100_LINK_RATE_BPS);
+ _tree->access<double>(mb_path / "tick_rate")
+ .subscribe(boost::bind(&tx_dsp_core_200::set_tick_rate, _tx_dsp, _1));
+ _tree->create<double>(mb_path / "tx_dsps/0/rate/value")
+ .coerce(boost::bind(&tx_dsp_core_200::set_host_rate, _tx_dsp, _1))
+ .subscribe(boost::bind(&b100_impl::update_tx_samp_rate, this, _1));
+ _tree->create<double>(mb_path / "tx_dsps/0/freq/value")
+ .coerce(boost::bind(&tx_dsp_core_200::set_freq, _tx_dsp, _1));
+ _tree->create<meta_range_t>(mb_path / "tx_dsps/0/freq/range")
+ .publish(boost::bind(&tx_dsp_core_200::get_freq_range, _tx_dsp));
+
+ ////////////////////////////////////////////////////////////////////
+ // create time control objects
+ ////////////////////////////////////////////////////////////////////
+ time64_core_200::readback_bases_type time64_rb_bases;
+ time64_rb_bases.rb_secs_now = B100_REG_RB_TIME_NOW_SECS;
+ time64_rb_bases.rb_ticks_now = B100_REG_RB_TIME_NOW_TICKS;
+ time64_rb_bases.rb_secs_pps = B100_REG_RB_TIME_PPS_SECS;
+ time64_rb_bases.rb_ticks_pps = B100_REG_RB_TIME_PPS_TICKS;
+ _time64 = time64_core_200::make(
+ _fpga_ctrl, B100_REG_SR_ADDR(B100_SR_TIME64), time64_rb_bases
+ );
+ _tree->access<double>(mb_path / "tick_rate")
+ .subscribe(boost::bind(&time64_core_200::set_tick_rate, _time64, _1));
+ _tree->create<time_spec_t>(mb_path / "time/now")
+ .publish(boost::bind(&time64_core_200::get_time_now, _time64))
+ .subscribe(boost::bind(&time64_core_200::set_time_now, _time64, _1));
+ _tree->create<time_spec_t>(mb_path / "time/pps")
+ .publish(boost::bind(&time64_core_200::get_time_last_pps, _time64))
+ .subscribe(boost::bind(&time64_core_200::set_time_next_pps, _time64, _1));
+ //setup time source props
+ _tree->create<std::string>(mb_path / "time_source/value")
+ .subscribe(boost::bind(&time64_core_200::set_time_source, _time64, _1));
+ _tree->create<std::vector<std::string> >(mb_path / "time_source/options")
+ .publish(boost::bind(&time64_core_200::get_time_sources, _time64));
+ //setup reference source props
+ _tree->create<std::string>(mb_path / "clock_source/value")
+ .subscribe(boost::bind(&b100_impl::update_clock_source, this, _1));
+ static const std::vector<std::string> clock_sources = boost::assign::list_of("internal")("external")("auto");
+ _tree->create<std::vector<std::string> >(mb_path / "clock_source/options").set(clock_sources);
+
+ ////////////////////////////////////////////////////////////////////
+ // create dboard control objects
+ ////////////////////////////////////////////////////////////////////
+
+ //read the dboard eeprom to extract the dboard ids
+ dboard_eeprom_t rx_db_eeprom, tx_db_eeprom, gdb_eeprom;
+ rx_db_eeprom.load(*_fpga_i2c_ctrl, I2C_ADDR_RX_A);
+ tx_db_eeprom.load(*_fpga_i2c_ctrl, I2C_ADDR_TX_A);
+ gdb_eeprom.load(*_fpga_i2c_ctrl, I2C_ADDR_TX_A ^ 5);
+
+ //create the properties and register subscribers
+ _tree->create<dboard_eeprom_t>(mb_path / "dboards/A/rx_eeprom")
+ .set(rx_db_eeprom)
+ .subscribe(boost::bind(&b100_impl::set_db_eeprom, this, "rx", _1));
+ _tree->create<dboard_eeprom_t>(mb_path / "dboards/A/tx_eeprom")
+ .set(tx_db_eeprom)
+ .subscribe(boost::bind(&b100_impl::set_db_eeprom, this, "tx", _1));
+ _tree->create<dboard_eeprom_t>(mb_path / "dboards/A/gdb_eeprom")
+ .set(gdb_eeprom)
+ .subscribe(boost::bind(&b100_impl::set_db_eeprom, this, "gdb", _1));
+
+ //create a new dboard interface and manager
+ _dboard_iface = make_b100_dboard_iface(_fpga_ctrl, _fpga_i2c_ctrl, _fpga_spi_ctrl, _clock_ctrl, _codec_ctrl);
+ _tree->create<dboard_iface::sptr>(mb_path / "dboards/A/iface").set(_dboard_iface);
+ _dboard_manager = dboard_manager::make(
+ rx_db_eeprom.id,
+ ((gdb_eeprom.id == dboard_id_t::none())? tx_db_eeprom : gdb_eeprom).id,
+ _dboard_iface
+ );
+ BOOST_FOREACH(const std::string &name, _dboard_manager->get_rx_subdev_names()){
+ dboard_manager::populate_prop_tree_from_subdev(
+ _tree->subtree(mb_path / "dboards/A/rx_frontends" / name),
+ _dboard_manager->get_rx_subdev(name)
+ );
+ }
+ BOOST_FOREACH(const std::string &name, _dboard_manager->get_tx_subdev_names()){
+ dboard_manager::populate_prop_tree_from_subdev(
+ _tree->subtree(mb_path / "dboards/A/tx_frontends" / name),
+ _dboard_manager->get_tx_subdev(name)
+ );
+ }
- //initialize the mboard
- mboard_init();
+ //initialize io handling
+ this->io_init();
- //initialize the dboards
- dboard_init();
+ ////////////////////////////////////////////////////////////////////
+ // do some post-init tasks
+ ////////////////////////////////////////////////////////////////////
+ _tree->access<double>(mb_path / "tick_rate").update() //update and then subscribe the clock callback
+ .subscribe(boost::bind(&b100_clock_ctrl::set_fpga_clock_rate, _clock_ctrl, _1));
- //initialize the dsps
- rx_ddc_init();
+ //and now that the tick rate is set, init the host rates to something
+ BOOST_FOREACH(const std::string &name, _tree->list(mb_path / "rx_dsps")){
+ _tree->access<double>(mb_path / "rx_dsps" / name / "rate" / "value").set(1e6);
+ }
+ BOOST_FOREACH(const std::string &name, _tree->list(mb_path / "tx_dsps")){
+ _tree->access<double>(mb_path / "tx_dsps" / name / "rate" / "value").set(1e6);
+ }
- //initialize the dsps
- tx_duc_init();
+ _tree->access<subdev_spec_t>(mb_path / "rx_subdev_spec").set(subdev_spec_t("A:"+_dboard_manager->get_rx_subdev_names()[0]));
+ _tree->access<subdev_spec_t>(mb_path / "tx_subdev_spec").set(subdev_spec_t("A:"+_dboard_manager->get_tx_subdev_names()[0]));
+ _tree->access<std::string>(mb_path / "clock_source/value").set("internal");
+ _tree->access<std::string>(mb_path / "time_source/value").set("none");
+}
- //init the subdev specs
- this->mboard_set(MBOARD_PROP_RX_SUBDEV_SPEC, subdev_spec_t());
- this->mboard_set(MBOARD_PROP_TX_SUBDEV_SPEC, subdev_spec_t());
+b100_impl::~b100_impl(void){
+ //set an empty async callback now that we deconstruct
+ _fpga_ctrl->set_async_cb(b100_ctrl::async_cb_type());
+}
- //initialize the send/recv buffs
- io_init();
+void b100_impl::check_fw_compat(void){
+ unsigned char data[4]; //useless data buffer
+ const boost::uint16_t fw_compat_num = _fx2_ctrl->usrp_control_read(
+ VRQ_FW_COMPAT, 0, 0, data, sizeof(data)
+ );
+ if (fw_compat_num != B100_FW_COMPAT_NUM){
+ throw uhd::runtime_error(str(boost::format(
+ "Expected firmware compatibility number 0x%x, but got 0x%x:\n"
+ "The firmware build is not compatible with the host code build."
+ ) % B100_FW_COMPAT_NUM % fw_compat_num));
+ }
}
-b100_impl::~b100_impl(void){
- /* NOP */
+void b100_impl::check_fpga_compat(void){
+ const boost::uint16_t fpga_compat_num = _fpga_ctrl->peek16(B100_REG_MISC_COMPAT);
+ if (fpga_compat_num != B100_FPGA_COMPAT_NUM){
+ throw uhd::runtime_error(str(boost::format(
+ "Expected FPGA compatibility number 0x%x, but got 0x%x:\n"
+ "The FPGA build is not compatible with the host code build."
+ ) % B100_FPGA_COMPAT_NUM % fpga_compat_num));
+ }
}
-bool b100_impl::recv_async_msg(uhd::async_metadata_t &md, double timeout){
- return _fpga_ctrl->recv_async_msg(md, timeout);
+double b100_impl::update_rx_codec_gain(const double gain){
+ //set gain on both I and Q, readback on one
+ //TODO in the future, gains should have individual control
+ _codec_ctrl->set_rx_pga_gain(gain, 'A');
+ _codec_ctrl->set_rx_pga_gain(gain, 'B');
+ return _codec_ctrl->get_rx_pga_gain('A');
}
-/***********************************************************************
- * Device Get
- **********************************************************************/
-void b100_impl::get(const wax::obj &key_, wax::obj &val)
-{
- named_prop_t key = named_prop_t::extract(key_);
+void b100_impl::set_mb_eeprom(const uhd::usrp::mboard_eeprom_t &mb_eeprom){
+ mb_eeprom.commit(*_fx2_ctrl, mboard_eeprom_t::MAP_B000);
+}
- //handle the get request conditioned on the key
- switch(key.as<device_prop_t>()){
- case DEVICE_PROP_NAME:
- val = std::string("USRP-B100 device");
- return;
+void b100_impl::set_db_eeprom(const std::string &type, const uhd::usrp::dboard_eeprom_t &db_eeprom){
+ if (type == "rx") db_eeprom.store(*_fpga_i2c_ctrl, I2C_ADDR_RX_A);
+ if (type == "tx") db_eeprom.store(*_fpga_i2c_ctrl, I2C_ADDR_TX_A);
+ if (type == "gdb") db_eeprom.store(*_fpga_i2c_ctrl, I2C_ADDR_TX_A ^ 5);
+}
- case DEVICE_PROP_MBOARD:
- UHD_ASSERT_THROW(key.name == "");
- val = _mboard_proxy->get_link();
- return;
+void b100_impl::update_clock_source(const std::string &source){
+ if (source == "auto") _clock_ctrl->use_auto_ref();
+ else if (source == "internal") _clock_ctrl->use_internal_ref();
+ else if (source == "external") _clock_ctrl->use_external_ref();
+ else throw uhd::runtime_error("unhandled clock configuration reference source: " + source);
+}
- case DEVICE_PROP_MBOARD_NAMES:
- val = prop_names_t(1, ""); //vector of size 1 with empty string
- return;
+////////////////// some GPIF preparation related stuff /////////////////
+void b100_impl::reset_gpif(const boost::uint16_t ep) {
+ _fx2_ctrl->usrp_control_write(VRQ_RESET_GPIF, ep, ep, 0, 0);
+}
- default: UHD_THROW_PROP_GET_ERROR();
- }
+void b100_impl::enable_gpif(const bool en) {
+ _fx2_ctrl->usrp_control_write(VRQ_ENABLE_GPIF, en ? 1 : 0, 0, 0, 0);
}
-/***********************************************************************
- * Device Set
- **********************************************************************/
-void b100_impl::set(const wax::obj &, const wax::obj &)
-{
- UHD_THROW_PROP_SET_ERROR();
+void b100_impl::clear_fpga_fifo(void) {
+ _fx2_ctrl->usrp_control_write(VRQ_CLEAR_FPGA_FIFO, 0, 0, 0, 0);
}
diff --git a/host/lib/usrp/b100/b100_impl.hpp b/host/lib/usrp/b100/b100_impl.hpp
index daec70bca..62a22674e 100644
--- a/host/lib/usrp/b100/b100_impl.hpp
+++ b/host/lib/usrp/b100/b100_impl.hpp
@@ -1,5 +1,5 @@
//
-// Copyright 2010 Ettus Research LLC
+// Copyright 2011 Ettus Research LLC
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -15,74 +15,56 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
-#include "b100_iface.hpp"
+#ifndef INCLUDED_B100_IMPL_HPP
+#define INCLUDED_B100_IMPL_HPP
+
+#include "fx2_ctrl.hpp"
#include "b100_ctrl.hpp"
#include "clock_ctrl.hpp"
#include "codec_ctrl.hpp"
+#include "spi_core_100.hpp"
+#include "i2c_core_100.hpp"
+#include "rx_frontend_core_200.hpp"
+#include "tx_frontend_core_200.hpp"
+#include "rx_dsp_core_200.hpp"
+#include "tx_dsp_core_200.hpp"
+#include "time64_core_200.hpp"
#include <uhd/device.hpp>
+#include <uhd/property_tree.hpp>
#include <uhd/utils/pimpl.hpp>
#include <uhd/types/dict.hpp>
#include <uhd/types/otw_type.hpp>
#include <uhd/types/clock_config.hpp>
#include <uhd/types/stream_cmd.hpp>
-#include <uhd/usrp/dboard_id.hpp>
+#include <uhd/usrp/mboard_eeprom.hpp>
#include <uhd/usrp/subdev_spec.hpp>
#include <uhd/usrp/dboard_eeprom.hpp>
#include <uhd/usrp/dboard_manager.hpp>
#include <uhd/transport/usb_zero_copy.hpp>
-#ifndef INCLUDED_B100_IMPL_HPP
-#define INCLUDED_B100_IMPL_HPP
+static const double B100_LINK_RATE_BPS = 256e6/8; //pratical link rate (< 480 Mbps)
+static const std::string B100_FW_FILE_NAME = "usrp_b100_fw.ihx";
+static const std::string B100_FPGA_FILE_NAME = "usrp_b100_fpga.bin";
+static const boost::uint16_t B100_FW_COMPAT_NUM = 0x02;
+static const boost::uint16_t B100_FPGA_COMPAT_NUM = 0x05;
+static const boost::uint32_t B100_RX_SID_BASE = 2;
+static const boost::uint32_t B100_TX_ASYNC_SID = 1;
+static const double B100_DEFAULT_TICK_RATE = 64e6;
-/*!
- * Make a b100 dboard interface.
- * \param iface the b100 interface object
- * \param clock the clock control interface
- * \param codec the codec control interface
- * \return a sptr to a new dboard interface
- */
+//! Make a b100 dboard interface
uhd::usrp::dboard_iface::sptr make_b100_dboard_iface(
- b100_iface::sptr iface,
+ wb_iface::sptr wb_iface,
+ uhd::i2c_iface::sptr i2c_iface,
+ uhd::spi_iface::sptr spi_iface,
b100_clock_ctrl::sptr clock,
b100_codec_ctrl::sptr codec
);
-/*!
- * Simple wax obj proxy class:
- * Provides a wax obj interface for a set and a get function.
- * This allows us to create nested properties structures
- * while maintaining flattened code within the implementation.
- */
-class wax_obj_proxy : public wax::obj {
-public:
- typedef boost::function<void(const wax::obj &, wax::obj &)> get_t;
- typedef boost::function<void(const wax::obj &, const wax::obj &)> set_t;
- typedef boost::shared_ptr<wax_obj_proxy> sptr;
-
- static sptr make(const get_t &get, const set_t &set){
- return sptr(new wax_obj_proxy(get, set));
- }
-
-private:
- get_t _get; set_t _set;
- wax_obj_proxy(const get_t &get, const set_t &set): _get(get), _set(set) {};
- void get(const wax::obj &key, wax::obj &val) {return _get(key, val);}
- void set(const wax::obj &key, const wax::obj &val) {return _set(key, val);}
-};
-
-/*!
- * USRP1 implementation guts:
- * The implementation details are encapsulated here.
- * Handles properties on the mboard, dboard, dsps...
- */
+//! Implementation guts
class b100_impl : public uhd::device {
public:
//structors
- b100_impl(uhd::transport::usb_zero_copy::sptr data_transport,
- uhd::transport::usb_zero_copy::sptr ctrl_transport,
- uhd::usrp::fx2_ctrl::sptr fx2_ctrl,
- double master_clock_rate);
-
+ b100_impl(const uhd::device_addr_t &);
~b100_impl(void);
//the io interface
@@ -91,114 +73,62 @@ public:
const uhd::tx_metadata_t &,
const uhd::io_type_t &,
send_mode_t, double);
-
size_t recv(const recv_buffs_type &,
size_t, uhd::rx_metadata_t &,
const uhd::io_type_t &,
recv_mode_t, double);
-
size_t get_max_send_samps_per_packet(void) const;
-
size_t get_max_recv_samps_per_packet(void) const;
-
bool recv_async_msg(uhd::async_metadata_t &, double);
private:
- //clock control
+ uhd::property_tree::sptr _tree;
+
+ //controllers
+ spi_core_100::sptr _fpga_spi_ctrl;
+ i2c_core_100::sptr _fpga_i2c_ctrl;
+ rx_frontend_core_200::sptr _rx_fe;
+ tx_frontend_core_200::sptr _tx_fe;
+ std::vector<rx_dsp_core_200::sptr> _rx_dsps;
+ tx_dsp_core_200::sptr _tx_dsp;
+ time64_core_200::sptr _time64;
b100_clock_ctrl::sptr _clock_ctrl;
-
- //interface to ioctls and file descriptor
- b100_iface::sptr _iface;
-
- //handle io stuff
- uhd::transport::zero_copy_if::sptr _data_transport;
- UHD_PIMPL_DECL(io_impl) _io_impl;
- void update_transport_channel_mapping(void);
- void io_init(void);
- void issue_stream_cmd(const uhd::stream_cmd_t &stream_cmd);
- void handle_overrun(size_t);
-
- //otw types
- uhd::otw_type_t _recv_otw_type;
- uhd::otw_type_t _send_otw_type;
-
- //configuration shadows
- uhd::clock_config_t _clock_config;
- uhd::usrp::subdev_spec_t _rx_subdev_spec, _tx_subdev_spec;
-
- //ad9862 codec control interface
b100_codec_ctrl::sptr _codec_ctrl;
+ b100_ctrl::sptr _fpga_ctrl;
+ uhd::usrp::fx2_ctrl::sptr _fx2_ctrl;
- //codec properties interfaces
- 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, _tx_codec_proxy;
-
- //device functions and settings
- void get(const wax::obj &, wax::obj &);
- void set(const wax::obj &, const wax::obj &);
-
- //mboard functions and settings
- void mboard_init(void);
- void mboard_get(const wax::obj &, wax::obj &);
- void mboard_set(const wax::obj &, const wax::obj &);
- void update_clock_config(void);
- wax_obj_proxy::sptr _mboard_proxy;
-
- /*!
- * Make a usrp1 dboard interface.
- * \param iface the usrp1 interface object
- * \param clock the clock control interface
- * \param codec the codec control interface
- * \param dboard_slot the slot identifier
- * \param rx_dboard_id the db id for the rx board (used for evil dbsrx purposes)
- * \return a sptr to a new dboard interface
- */
- static uhd::usrp::dboard_iface::sptr make_dboard_iface(
- b100_iface::sptr iface,
- b100_clock_ctrl::sptr clock,
- b100_codec_ctrl::sptr codec,
- const uhd::usrp::dboard_id_t &rx_dboard_id
- );
+ //transports
+ uhd::transport::zero_copy_if::sptr _data_transport, _ctrl_transport;
- //xx dboard functions and settings
- void dboard_init(void);
+ //dboard stuff
uhd::usrp::dboard_manager::sptr _dboard_manager;
uhd::usrp::dboard_iface::sptr _dboard_iface;
- //rx dboard functions and settings
- uhd::usrp::dboard_eeprom_t _rx_db_eeprom;
- 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;
-
- //tx dboard functions and settings
- uhd::usrp::dboard_eeprom_t _tx_db_eeprom, _gdb_eeprom;
- 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;
-
- //rx ddc functions and settings
- void rx_ddc_init(void);
- void rx_ddc_get(const wax::obj &, wax::obj &);
- void rx_ddc_set(const wax::obj &, const wax::obj &);
- double _ddc_freq; size_t _ddc_decim;
- wax_obj_proxy::sptr _rx_ddc_proxy;
-
- //tx duc functions and settings
- void tx_duc_init(void);
- void tx_duc_get(const wax::obj &, wax::obj &);
- void tx_duc_set(const wax::obj &, const wax::obj &);
- double _duc_freq; size_t _duc_interp;
- wax_obj_proxy::sptr _tx_duc_proxy;
+ //handle io stuff
+ uhd::otw_type_t _rx_otw_type, _tx_otw_type;
+ UHD_PIMPL_DECL(io_impl) _io_impl;
+ void io_init(void);
- //transports
- b100_ctrl::sptr _fpga_ctrl;
- uhd::usrp::fx2_ctrl::sptr _fx2_ctrl;
+ //device properties interface
+ void get(const wax::obj &, wax::obj &val){
+ val = _tree; //entry point into property tree
+ }
+ void check_fw_compat(void);
+ void check_fpga_compat(void);
+ double update_rx_codec_gain(const double); //sets A and B at once
+ void set_mb_eeprom(const uhd::usrp::mboard_eeprom_t &);
+ void set_db_eeprom(const std::string &, const uhd::usrp::dboard_eeprom_t &);
+ void update_tick_rate(const double rate);
+ void update_rx_samp_rate(const double rate);
+ void update_tx_samp_rate(const double rate);
+ void update_rx_subdev_spec(const uhd::usrp::subdev_spec_t &);
+ void update_tx_subdev_spec(const uhd::usrp::subdev_spec_t &);
+ void update_clock_source(const std::string &);
+ void reset_gpif(const boost::uint16_t);
+ void enable_gpif(const bool);
+ void clear_fpga_fifo(void);
+ void handle_async_message(uhd::transport::managed_recv_buffer::sptr);
};
#endif /* INCLUDED_b100_IMPL_HPP */
diff --git a/host/lib/usrp/b100/b100_regs.hpp b/host/lib/usrp/b100/b100_regs.hpp
index 010df283e..5e24f9937 100644
--- a/host/lib/usrp/b100/b100_regs.hpp
+++ b/host/lib/usrp/b100/b100_regs.hpp
@@ -10,14 +10,13 @@
// This means that address bit 0 is usually 0.
// There are 11 bits of address for the control.
-#ifndef __B100_REGS_H
-#define __B100_REGS_H
+#ifndef INCLUDED_B100_REGS_HPP
+#define INCLUDED_B100_REGS_HPP
/////////////////////////////////////////////////////
// Slave pointers
#define B100_REG_SLAVE(n) ((n)<<7)
-#define B100_REG_SR_ADDR(n) ((B100_REG_SETTINGS_BASE) + (4*(n)))
/////////////////////////////////////////////////////
// Slave 0 -- Misc Regs
@@ -51,64 +50,16 @@
//these are 32-bit registers mapped onto the 16-bit Wishbone bus.
//Using peek32/poke32 should allow transparent use of these registers.
#define B100_REG_SPI_BASE B100_REG_SLAVE(2)
-#define B100_REG_SPI_TXRX0 B100_REG_SPI_BASE + 0
-#define B100_REG_SPI_TXRX1 B100_REG_SPI_BASE + 4
-#define B100_REG_SPI_TXRX2 B100_REG_SPI_BASE + 8
-#define B100_REG_SPI_TXRX3 B100_REG_SPI_BASE + 12
-#define B100_REG_SPI_CTRL B100_REG_SPI_BASE + 16
-#define B100_REG_SPI_DIV B100_REG_SPI_BASE + 20
-#define B100_REG_SPI_SS B100_REG_SPI_BASE + 24
//spi slave constants
#define B100_SPI_SS_AD9862 (1 << 2)
#define B100_SPI_SS_TX_DB (1 << 1)
#define B100_SPI_SS_RX_DB (1 << 0)
-//spi ctrl register bit definitions
-#define SPI_CTRL_ASS (1<<13)
-#define SPI_CTRL_IE (1<<12)
-#define SPI_CTRL_LSB (1<<11)
-#define SPI_CTRL_TXNEG (1<<10) //mosi edge, push on falling edge when 1
-#define SPI_CTRL_RXNEG (1<< 9) //miso edge, latch on falling edge when 1
-#define SPI_CTRL_GO_BSY (1<< 8)
-#define SPI_CTRL_CHAR_LEN_MASK 0x7F
-
////////////////////////////////////////////////
// Slave 3 -- I2C Core
#define B100_REG_I2C_BASE B100_REG_SLAVE(3)
-#define B100_REG_I2C_PRESCALER_LO B100_REG_I2C_BASE + 0
-#define B100_REG_I2C_PRESCALER_HI B100_REG_I2C_BASE + 2
-#define B100_REG_I2C_CTRL B100_REG_I2C_BASE + 4
-#define B100_REG_I2C_DATA B100_REG_I2C_BASE + 6
-#define B100_REG_I2C_CMD_STATUS B100_REG_I2C_BASE + 8
-
-//and while we're here...
-
-//
-// STA, STO, RD, WR, and IACK bits are cleared automatically
-//
-
-#define I2C_CTRL_EN (1 << 7) // core enable
-#define I2C_CTRL_IE (1 << 6) // interrupt enable
-
-#define I2C_CMD_START (1 << 7) // generate (repeated) start condition
-#define I2C_CMD_STOP (1 << 6) // generate stop condition
-#define I2C_CMD_RD (1 << 5) // read from slave
-#define I2C_CMD_WR (1 << 4) // write to slave
-#define I2C_CMD_NACK (1 << 3) // when a rcvr, send ACK (ACK=0) or NACK (ACK=1)
-#define I2C_CMD_RSVD_2 (1 << 2) // reserved
-#define I2C_CMD_RSVD_1 (1 << 1) // reserved
-#define I2C_CMD_IACK (1 << 0) // set to clear pending interrupt
-
-#define I2C_ST_RXACK (1 << 7) // Received acknowledgement from slave (1 = NAK, 0 = ACK)
-#define I2C_ST_BUSY (1 << 6) // 1 after START signal detected; 0 after STOP signal detected
-#define I2C_ST_AL (1 << 5) // Arbitration lost. 1 when core lost arbitration
-#define I2C_ST_RSVD_4 (1 << 4) // reserved
-#define I2C_ST_RSVD_3 (1 << 3) // reserved
-#define I2C_ST_RSVD_2 (1 << 2) // reserved
-#define I2C_ST_TIP (1 << 1) // Transfer-in-progress
-#define I2C_ST_IP (1 << 0) // Interrupt pending
////////////////////////////////////////////////
// Slave 4 -- GPIO
@@ -164,101 +115,33 @@
// Output-only, no readback, 64 registers total
// Each register must be written 32 bits at a time
// First the address xxx_xx00 and then xxx_xx10
+// 64 total regs in address space
+#define B100_SR_RX_CTRL0 0 // 9 regs (+0 to +8)
+#define B100_SR_RX_DSP0 10 // 4 regs (+0 to +3)
+#define B100_SR_RX_CTRL1 16 // 9 regs (+0 to +8)
+#define B100_SR_RX_DSP1 26 // 4 regs (+0 to +3)
+#define B100_SR_TX_CTRL 32 // 4 regs (+0 to +3)
+#define B100_SR_TX_DSP 38 // 3 regs (+0 to +2)
-#define B100_REG_SETTINGS_BASE_ADDR(n) (B100_REG_SLAVE(8) + (4*(n)))
-
-#define B100_REG_SR_MISC_TEST32 B100_REG_SETTINGS_BASE_ADDR(52)
+#define B100_SR_TIME64 42 // 6 regs (+0 to +5)
+#define B100_SR_RX_FRONT 48 // 5 regs (+0 to +4)
+#define B100_SR_TX_FRONT 54 // 5 regs (+0 to +4)
-/////////////////////////////////////////////////
-// DSP RX Regs
-////////////////////////////////////////////////
-#define B100_REG_DSP_RX_ADDR(n) (B100_REG_SETTINGS_BASE_ADDR(16) + (4*(n)))
-#define B100_REG_DSP_RX_FREQ B100_REG_DSP_RX_ADDR(0)
-#define B100_REG_DSP_RX_SCALE_IQ B100_REG_DSP_RX_ADDR(1) // {scale_i,scale_q}
-#define B100_REG_DSP_RX_DECIM_RATE B100_REG_DSP_RX_ADDR(2) // hb and decim rate
-#define B100_REG_DSP_RX_DCOFFSET_I B100_REG_DSP_RX_ADDR(3) // Bit 31 high sets fixed offset mode, using lower 14 bits, // otherwise it is automatic
-#define B100_REG_DSP_RX_DCOFFSET_Q B100_REG_DSP_RX_ADDR(4) // Bit 31 high sets fixed offset mode, using lower 14 bits
-#define B100_REG_DSP_RX_MUX B100_REG_DSP_RX_ADDR(5)
+#define B100_SR_REG_TEST32 60 // 1 reg
+#define B100_SR_CLEAR_RX_FIFO 61 // 1 reg
+#define B100_SR_CLEAR_TX_FIFO 62 // 1 reg
+#define B100_SR_GLOBAL_RESET 63 // 1 reg
-///////////////////////////////////////////////////
-// VITA RX CTRL regs
-///////////////////////////////////////////////////
-// The following 3 are logically a single command register.
-// They are clocked into the underlying fifo when time_ticks is written.
-#define B100_REG_CTRL_RX_ADDR(n) (B100_REG_SETTINGS_BASE_ADDR(0) + (4*(n)))
-#define B100_REG_CTRL_RX_STREAM_CMD B100_REG_CTRL_RX_ADDR(0) // {now, chain, num_samples(30)
-#define B100_REG_CTRL_RX_TIME_SECS B100_REG_CTRL_RX_ADDR(1)
-#define B100_REG_CTRL_RX_TIME_TICKS B100_REG_CTRL_RX_ADDR(2)
-#define B100_REG_CTRL_RX_CLEAR_OVERRUN B100_REG_CTRL_RX_ADDR(3) // write anything to clear overrun
-#define B100_REG_CTRL_RX_VRT_HEADER B100_REG_CTRL_RX_ADDR(4) // word 0 of packet. FPGA fills in packet counter
-#define B100_REG_CTRL_RX_VRT_STREAM_ID B100_REG_CTRL_RX_ADDR(5) // word 1 of packet.
-#define B100_REG_CTRL_RX_VRT_TRAILER B100_REG_CTRL_RX_ADDR(6)
-#define B100_REG_CTRL_RX_NSAMPS_PER_PKT B100_REG_CTRL_RX_ADDR(7)
-#define B100_REG_CTRL_RX_NCHANNELS B100_REG_CTRL_RX_ADDR(8) // 1 in basic case, up to 4 for vector sources
-
-/////////////////////////////////////////////////
-// DSP TX Regs
-////////////////////////////////////////////////
-#define B100_REG_DSP_TX_ADDR(n) (B100_REG_SETTINGS_BASE_ADDR(32) + (4*(n)))
-#define B100_REG_DSP_TX_FREQ B100_REG_DSP_TX_ADDR(0)
-#define B100_REG_DSP_TX_SCALE_IQ B100_REG_DSP_TX_ADDR(1) // {scale_i,scale_q}
-#define B100_REG_DSP_TX_INTERP_RATE B100_REG_DSP_TX_ADDR(2)
-#define B100_REG_DSP_TX_UNUSED B100_REG_DSP_TX_ADDR(3)
-#define B100_REG_DSP_TX_MUX B100_REG_DSP_TX_ADDR(4)
-
-/////////////////////////////////////////////////
-// VITA TX CTRL regs
-////////////////////////////////////////////////
-#define B100_REG_CTRL_TX_ADDR(n) (B100_REG_SETTINGS_BASE_ADDR(24) + (4*(n)))
-#define B100_REG_CTRL_TX_NCHANNELS B100_REG_CTRL_TX_ADDR(0)
-#define B100_REG_CTRL_TX_CLEAR_UNDERRUN B100_REG_CTRL_TX_ADDR(1)
-#define B100_REG_CTRL_TX_REPORT_SID B100_REG_CTRL_TX_ADDR(2)
-#define B100_REG_CTRL_TX_POLICY B100_REG_CTRL_TX_ADDR(3)
+#define B100_REG_SR_ADDR(n) (B100_REG_SLAVE(8) + (4*(n)))
-#define B100_FLAG_CTRL_TX_POLICY_WAIT (0x1 << 0)
-#define B100_FLAG_CTRL_TX_POLICY_NEXT_PACKET (0x1 << 1)
-#define B100_FLAG_CTRL_TX_POLICY_NEXT_BURST (0x1 << 2)
+#define B100_REG_SR_MISC_TEST32 B100_REG_SR_ADDR(B100_SR_REG_TEST32)
/////////////////////////////////////////////////
-// VITA49 64 bit time (write only)
+// Magic reset regs
////////////////////////////////////////////////
- /*!
- * \brief Time 64 flags
- *
- * <pre>
- *
- * 3 2 1
- * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
- * +-----------------------------------------------------------+-+-+
- * | |S|P|
- * +-----------------------------------------------------------+-+-+
- *
- * P - PPS edge selection (0=negedge, 1=posedge, default=0)
- * S - Source (0=sma, 1=mimo, 0=default)
- *
- * </pre>
- */
-#define B100_REG_TIME64_ADDR(n) (B100_REG_SETTINGS_BASE_ADDR(40) + (4*(n)))
-#define B100_REG_TIME64_SECS B100_REG_TIME64_ADDR(0) // value to set absolute secs to on next PPS
-#define B100_REG_TIME64_TICKS B100_REG_TIME64_ADDR(1) // value to set absolute ticks to on next PPS
-#define B100_REG_TIME64_FLAGS B100_REG_TIME64_ADDR(2) // flags - see chart above
-#define B100_REG_TIME64_IMM B100_REG_TIME64_ADDR(3) // set immediate (0=latch on next pps, 1=latch immediate, default=0)
-#define B100_REG_TIME64_TPS B100_REG_TIME64_ADDR(4) // clock ticks per second (counter rollover)
-
-//pps flags (see above)
-#define B100_FLAG_TIME64_PPS_NEGEDGE (0 << 0)
-#define B100_FLAG_TIME64_PPS_POSEDGE (1 << 0)
-#define B100_FLAG_TIME64_PPS_SMA (0 << 1)
-#define B100_FLAG_TIME64_PPS_MIMO (1 << 1)
-
-#define B100_FLAG_TIME64_LATCH_NOW 1
-#define B100_FLAG_TIME64_LATCH_NEXT_PPS 0
-
-#define B100_REG_CLEAR_RX_FIFO B100_REG_SETTINGS_BASE_ADDR(48)
-#define B100_REG_CLEAR_TX_FIFO B100_REG_SETTINGS_BASE_ADDR(49)
-
-#define B100_REG_GLOBAL_RESET B100_REG_SETTINGS_BASE_ADDR(50)
-#define B100_REG_TEST32 B100_REG_SETTINGS_BASE_ADDR(52)
+#define B100_REG_CLEAR_RX B100_REG_SR_ADDR(B100_SR_CLEAR_RX_FIFO)
+#define B100_REG_CLEAR_TX B100_REG_SR_ADDR(B100_SR_CLEAR_RX_FIFO)
+#define B100_REG_GLOBAL_RESET B100_REG_SR_ADDR(B100_SR_GLOBAL_RESET)
#endif
diff --git a/host/lib/usrp/b100/clock_ctrl.cpp b/host/lib/usrp/b100/clock_ctrl.cpp
index e138242d1..c93ff64c7 100644
--- a/host/lib/usrp/b100/clock_ctrl.cpp
+++ b/host/lib/usrp/b100/clock_ctrl.cpp
@@ -1,5 +1,5 @@
//
-// Copyright 2010-2011 Ettus Research LLC
+// Copyright 2011 Ettus Research LLC
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -169,11 +169,17 @@ static clock_settings_type get_clock_settings(double rate){
**********************************************************************/
class b100_clock_ctrl_impl : public b100_clock_ctrl{
public:
- b100_clock_ctrl_impl(b100_iface::sptr iface, double master_clock_rate){
+ b100_clock_ctrl_impl(i2c_iface::sptr iface, double master_clock_rate){
_iface = iface;
_chan_rate = 0.0;
_out_rate = 0.0;
+ //perform soft-reset
+ _ad9522_regs.soft_reset = 1;
+ this->send_reg(0x000);
+ this->latch_regs();
+ _ad9522_regs.soft_reset = 0;
+
//init the clock gen registers
_ad9522_regs.sdo_active = ad9522_regs_t::SDO_ACTIVE_SDO_SDIO;
_ad9522_regs.enb_stat_eeprom_at_stat_pin = 0; //use status pin
@@ -294,7 +300,6 @@ public:
//clock rate changed! update dboard clocks and FPGA ticks per second
set_rx_dboard_clock_rate(rate);
set_tx_dboard_clock_rate(rate);
- _iface->poke32(B100_REG_TIME64_TPS, boost::uint32_t(get_fpga_clock_rate()));
}
double get_fpga_clock_rate(void){
@@ -428,7 +433,7 @@ public:
}
private:
- b100_iface::sptr _iface;
+ i2c_iface::sptr _iface;
ad9522_regs_t _ad9522_regs;
double _out_rate; //rate at the fpga and codec
double _chan_rate; //rate before final dividers
@@ -447,16 +452,16 @@ private:
buf.push_back(boost::uint8_t(reg >> 8));
buf.push_back(boost::uint8_t(reg & 0xff));
- _iface->get_fx2_i2c_iface().write_i2c(0x5C, buf);
+ _iface->write_i2c(0x5C, buf);
}
boost::uint8_t read_reg(boost::uint16_t addr){
byte_vector_t buf;
buf.push_back(boost::uint8_t(addr >> 8));
buf.push_back(boost::uint8_t(addr & 0xff));
- _iface->get_fx2_i2c_iface().write_i2c(0x5C, buf);
+ _iface->write_i2c(0x5C, buf);
- buf = _iface->get_fx2_i2c_iface().read_i2c(0x5C, 1);
+ buf = _iface->read_i2c(0x5C, 1);
return boost::uint32_t(buf[0] & 0xFF);
}
@@ -520,6 +525,6 @@ private:
/***********************************************************************
* Clock Control Make
**********************************************************************/
-b100_clock_ctrl::sptr b100_clock_ctrl::make(b100_iface::sptr iface, double master_clock_rate){
+b100_clock_ctrl::sptr b100_clock_ctrl::make(i2c_iface::sptr iface, double master_clock_rate){
return sptr(new b100_clock_ctrl_impl(iface, master_clock_rate));
}
diff --git a/host/lib/usrp/b100/clock_ctrl.hpp b/host/lib/usrp/b100/clock_ctrl.hpp
index 2a2e74024..5ef231281 100644
--- a/host/lib/usrp/b100/clock_ctrl.hpp
+++ b/host/lib/usrp/b100/clock_ctrl.hpp
@@ -1,5 +1,5 @@
//
-// Copyright 2010 Ettus Research LLC
+// Copyright 2011 Ettus Research LLC
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -18,7 +18,7 @@
#ifndef INCLUDED_B100_CLOCK_CTRL_HPP
#define INCLUDED_B100_CLOCK_CTRL_HPP
-#include "b100_iface.hpp"
+#include <uhd/types/serial.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/utility.hpp>
#include <vector>
@@ -34,11 +34,11 @@ public:
/*!
* Make a new clock control object.
- * \param iface the b100 iface object
+ * \param iface the controller iface object
* \param master_clock_rate the master FPGA/sample clock rate
* \return the clock control object
*/
- static sptr make(b100_iface::sptr iface, double master_clock_rate);
+ static sptr make(uhd::i2c_iface::sptr iface, double master_clock_rate);
/*!
* Set the rate of the fpga clock line.
diff --git a/host/lib/usrp/b100/codec_ctrl.cpp b/host/lib/usrp/b100/codec_ctrl.cpp
index 4d118b68b..4f9036039 100644
--- a/host/lib/usrp/b100/codec_ctrl.cpp
+++ b/host/lib/usrp/b100/codec_ctrl.cpp
@@ -1,5 +1,5 @@
//
-// Copyright 2010 Ettus Research LLC
+// Copyright 2011 Ettus Research LLC
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -39,7 +39,7 @@ const gain_range_t b100_codec_ctrl::rx_pga_gain_range(0, 20, 1);
class b100_codec_ctrl_impl : public b100_codec_ctrl{
public:
//structors
- b100_codec_ctrl_impl(b100_iface::sptr iface);
+ b100_codec_ctrl_impl(spi_iface::sptr iface);
~b100_codec_ctrl_impl(void);
//aux adc and dac control
@@ -53,7 +53,7 @@ public:
double get_rx_pga_gain(char);
private:
- b100_iface::sptr _iface;
+ spi_iface::sptr _iface;
ad9862_regs_t _ad9862_regs;
void send_reg(boost::uint8_t addr);
void recv_reg(boost::uint8_t addr);
@@ -62,7 +62,7 @@ private:
/***********************************************************************
* Codec Control Structors
**********************************************************************/
-b100_codec_ctrl_impl::b100_codec_ctrl_impl(b100_iface::sptr iface){
+b100_codec_ctrl_impl::b100_codec_ctrl_impl(spi_iface::sptr iface){
_iface = iface;
//soft reset
@@ -278,6 +278,6 @@ void b100_codec_ctrl_impl::recv_reg(boost::uint8_t addr){
/***********************************************************************
* Codec Control Make
**********************************************************************/
-b100_codec_ctrl::sptr b100_codec_ctrl::make(b100_iface::sptr iface){
+b100_codec_ctrl::sptr b100_codec_ctrl::make(spi_iface::sptr iface){
return sptr(new b100_codec_ctrl_impl(iface));
}
diff --git a/host/lib/usrp/b100/codec_ctrl.hpp b/host/lib/usrp/b100/codec_ctrl.hpp
index 1bd579190..1f7bdef09 100644
--- a/host/lib/usrp/b100/codec_ctrl.hpp
+++ b/host/lib/usrp/b100/codec_ctrl.hpp
@@ -1,5 +1,5 @@
//
-// Copyright 2010 Ettus Research LLC
+// Copyright 2011 Ettus Research LLC
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -18,7 +18,7 @@
#ifndef INCLUDED_B100_CODEC_CTRL_HPP
#define INCLUDED_B100_CODEC_CTRL_HPP
-#include "b100_iface.hpp"
+#include <uhd/types/serial.hpp>
#include <uhd/types/ranges.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/utility.hpp>
@@ -40,7 +40,7 @@ public:
* \param iface the usrp_e iface object
* \return the codec control object
*/
- static sptr make(b100_iface::sptr iface);
+ static sptr make(uhd::spi_iface::sptr iface);
//! aux adc identifier constants
enum aux_adc_t{
diff --git a/host/lib/usrp/b100/codec_impl.cpp b/host/lib/usrp/b100/codec_impl.cpp
deleted file mode 100644
index de3ca3a66..000000000
--- a/host/lib/usrp/b100/codec_impl.cpp
+++ /dev/null
@@ -1,149 +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 "b100_impl.hpp"
-#include <uhd/exception.hpp>
-#include <uhd/usrp/codec_props.hpp>
-#include <boost/bind.hpp>
-
-using namespace uhd;
-using namespace uhd::usrp;
-
-/***********************************************************************
- * Helper Methods
- **********************************************************************/
-void b100_impl::codec_init(void){
- //make proxies
- _rx_codec_proxy = wax_obj_proxy::make(
- boost::bind(&b100_impl::rx_codec_get, this, _1, _2),
- boost::bind(&b100_impl::rx_codec_set, this, _1, _2)
- );
- _tx_codec_proxy = wax_obj_proxy::make(
- boost::bind(&b100_impl::tx_codec_get, this, _1, _2),
- boost::bind(&b100_impl::tx_codec_set, this, _1, _2)
- );
-}
-
-/***********************************************************************
- * RX Codec Properties
- **********************************************************************/
-static const std::string ad9862_pga_gain_name = "ad9862 pga";
-
-void b100_impl::rx_codec_get(const wax::obj &key_, wax::obj &val){
- named_prop_t key = named_prop_t::extract(key_);
-
- //handle the get request conditioned on the key
- switch(key.as<codec_prop_t>()){
- case CODEC_PROP_NAME:
- val = std::string("b100 adc - ad9522");
- return;
-
- case CODEC_PROP_OTHERS:
- val = prop_names_t();
- return;
-
- case CODEC_PROP_GAIN_NAMES:
- val = prop_names_t(1, ad9862_pga_gain_name);
- return;
-
- case CODEC_PROP_GAIN_RANGE:
- UHD_ASSERT_THROW(key.name == ad9862_pga_gain_name);
- val = b100_codec_ctrl::rx_pga_gain_range;
- return;
-
- case CODEC_PROP_GAIN_I:
- UHD_ASSERT_THROW(key.name == ad9862_pga_gain_name);
- val = _codec_ctrl->get_rx_pga_gain('A');
- return;
-
- case CODEC_PROP_GAIN_Q:
- UHD_ASSERT_THROW(key.name == ad9862_pga_gain_name);
- val = _codec_ctrl->get_rx_pga_gain('B');
- return;
-
- default: UHD_THROW_PROP_GET_ERROR();
- }
-}
-
-void b100_impl::rx_codec_set(const wax::obj &key_, const wax::obj &val){
- named_prop_t key = named_prop_t::extract(key_);
-
- //handle the set request conditioned on the key
- switch(key.as<codec_prop_t>()){
- case CODEC_PROP_GAIN_I:
- UHD_ASSERT_THROW(key.name == ad9862_pga_gain_name);
- _codec_ctrl->set_rx_pga_gain(val.as<double>(), 'A');
- return;
-
- case CODEC_PROP_GAIN_Q:
- UHD_ASSERT_THROW(key.name == ad9862_pga_gain_name);
- _codec_ctrl->set_rx_pga_gain(val.as<double>(), 'B');
- return;
-
- default: UHD_THROW_PROP_SET_ERROR();
- }
-}
-
-/***********************************************************************
- * TX Codec Properties
- **********************************************************************/
-void b100_impl::tx_codec_get(const wax::obj &key_, wax::obj &val){
- named_prop_t key = named_prop_t::extract(key_);
-
- //handle the get request conditioned on the key
- switch(key.as<codec_prop_t>()){
- case CODEC_PROP_NAME:
- val = std::string("b100 dac - ad9522");
- return;
-
- case CODEC_PROP_OTHERS:
- val = prop_names_t();
- return;
-
- case CODEC_PROP_GAIN_NAMES:
- val = prop_names_t(1, ad9862_pga_gain_name);
- return;
-
- case CODEC_PROP_GAIN_RANGE:
- UHD_ASSERT_THROW(key.name == ad9862_pga_gain_name);
- val = b100_codec_ctrl::tx_pga_gain_range;
- return;
-
- case CODEC_PROP_GAIN_I: //only one gain for I and Q
- case CODEC_PROP_GAIN_Q:
- UHD_ASSERT_THROW(key.name == ad9862_pga_gain_name);
- val = _codec_ctrl->get_tx_pga_gain();
- return;
-
- default: UHD_THROW_PROP_GET_ERROR();
- }
-}
-
-void b100_impl::tx_codec_set(const wax::obj &key_, const wax::obj &val){
- named_prop_t key = named_prop_t::extract(key_);
-
- //handle the set request conditioned on the key
- switch(key.as<codec_prop_t>()){
- case CODEC_PROP_GAIN_I: //only one gain for I and Q
- case CODEC_PROP_GAIN_Q:
- UHD_ASSERT_THROW(key.name == ad9862_pga_gain_name);
- _codec_ctrl->set_tx_pga_gain(val.as<double>());
- return;
-
- default: UHD_THROW_PROP_SET_ERROR();
- }
-}
diff --git a/host/lib/usrp/b100/ctrl_packet.hpp b/host/lib/usrp/b100/ctrl_packet.hpp
index f504fc5aa..bab1f0de1 100644
--- a/host/lib/usrp/b100/ctrl_packet.hpp
+++ b/host/lib/usrp/b100/ctrl_packet.hpp
@@ -1,5 +1,5 @@
//
-// Copyright 2010 Ettus Research LLC
+// Copyright 2011 Ettus Research LLC
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
diff --git a/host/lib/usrp/b100/dboard_iface.cpp b/host/lib/usrp/b100/dboard_iface.cpp
index ec3da6220..33c4b355d 100644
--- a/host/lib/usrp/b100/dboard_iface.cpp
+++ b/host/lib/usrp/b100/dboard_iface.cpp
@@ -1,5 +1,5 @@
//
-// Copyright 2010 Ettus Research LLC
+// Copyright 2011 Ettus Research LLC
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -15,7 +15,8 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
-#include "b100_iface.hpp"
+#include "wb_iface.hpp"
+#include <uhd/types/serial.hpp>
#include "b100_regs.hpp"
#include "clock_ctrl.hpp"
#include "codec_ctrl.hpp"
@@ -33,11 +34,15 @@ class b100_dboard_iface : public dboard_iface{
public:
b100_dboard_iface(
- b100_iface::sptr iface,
+ wb_iface::sptr wb_iface,
+ i2c_iface::sptr i2c_iface,
+ spi_iface::sptr spi_iface,
b100_clock_ctrl::sptr clock,
b100_codec_ctrl::sptr codec
){
- _iface = iface;
+ _wb_iface = wb_iface;
+ _i2c_iface = i2c_iface;
+ _spi_iface = spi_iface;
_clock = clock;
_codec = codec;
@@ -45,8 +50,8 @@ public:
this->set_clock_rate(UNIT_RX, _clock->get_fpga_clock_rate());
this->set_clock_rate(UNIT_TX, _clock->get_fpga_clock_rate());
- _iface->poke16(B100_REG_GPIO_RX_DBG, 0);
- _iface->poke16(B100_REG_GPIO_TX_DBG, 0);
+ _wb_iface->poke16(B100_REG_GPIO_RX_DBG, 0);
+ _wb_iface->poke16(B100_REG_GPIO_TX_DBG, 0);
}
~b100_dboard_iface(void){
@@ -94,7 +99,9 @@ public:
double get_codec_rate(unit_t);
private:
- b100_iface::sptr _iface;
+ wb_iface::sptr _wb_iface;
+ i2c_iface::sptr _i2c_iface;
+ spi_iface::sptr _spi_iface;
b100_clock_ctrl::sptr _clock;
b100_codec_ctrl::sptr _codec;
uhd::dict<unit_t, double> _clock_rates;
@@ -104,11 +111,13 @@ private:
* Make Function
**********************************************************************/
dboard_iface::sptr make_b100_dboard_iface(
- b100_iface::sptr iface,
+ wb_iface::sptr wb_iface,
+ i2c_iface::sptr i2c_iface,
+ spi_iface::sptr spi_iface,
b100_clock_ctrl::sptr clock,
b100_codec_ctrl::sptr codec
){
- return dboard_iface::sptr(new b100_dboard_iface(iface, clock, codec));
+ return dboard_iface::sptr(new b100_dboard_iface(wb_iface, i2c_iface, spi_iface, clock, codec));
}
/***********************************************************************
@@ -151,29 +160,29 @@ double b100_dboard_iface::get_codec_rate(unit_t){
void b100_dboard_iface::_set_pin_ctrl(unit_t unit, boost::uint16_t value){
UHD_ASSERT_THROW(GPIO_SEL_ATR == 1); //make this assumption
switch(unit){
- case UNIT_RX: _iface->poke16(B100_REG_GPIO_RX_SEL, value); return;
- case UNIT_TX: _iface->poke16(B100_REG_GPIO_TX_SEL, value); return;
+ case UNIT_RX: _wb_iface->poke16(B100_REG_GPIO_RX_SEL, value); return;
+ case UNIT_TX: _wb_iface->poke16(B100_REG_GPIO_TX_SEL, value); return;
}
}
void b100_dboard_iface::_set_gpio_ddr(unit_t unit, boost::uint16_t value){
switch(unit){
- case UNIT_RX: _iface->poke16(B100_REG_GPIO_RX_DDR, value); return;
- case UNIT_TX: _iface->poke16(B100_REG_GPIO_TX_DDR, value); return;
+ case UNIT_RX: _wb_iface->poke16(B100_REG_GPIO_RX_DDR, value); return;
+ case UNIT_TX: _wb_iface->poke16(B100_REG_GPIO_TX_DDR, value); return;
}
}
void b100_dboard_iface::_set_gpio_out(unit_t unit, boost::uint16_t value){
switch(unit){
- case UNIT_RX: _iface->poke16(B100_REG_GPIO_RX_IO, value); return;
- case UNIT_TX: _iface->poke16(B100_REG_GPIO_TX_IO, value); return;
+ case UNIT_RX: _wb_iface->poke16(B100_REG_GPIO_RX_IO, value); return;
+ case UNIT_TX: _wb_iface->poke16(B100_REG_GPIO_TX_IO, value); return;
}
}
boost::uint16_t b100_dboard_iface::read_gpio(unit_t unit){
switch(unit){
- case UNIT_RX: return _iface->peek16(B100_REG_GPIO_RX_IO);
- case UNIT_TX: return _iface->peek16(B100_REG_GPIO_TX_IO);
+ case UNIT_RX: return _wb_iface->peek16(B100_REG_GPIO_RX_IO);
+ case UNIT_TX: return _wb_iface->peek16(B100_REG_GPIO_TX_IO);
default: UHD_THROW_INVALID_CODE_PATH();
}
}
@@ -196,7 +205,7 @@ void b100_dboard_iface::_set_atr_reg(unit_t unit, atr_reg_t atr, boost::uint16_t
(ATR_REG_FULL_DUPLEX, B100_REG_ATR_FULL_TXSIDE)
)
;
- _iface->poke16(unit_to_atr_to_addr[unit][atr], value);
+ _wb_iface->poke16(unit_to_atr_to_addr[unit][atr], value);
}
void b100_dboard_iface::set_gpio_debug(unit_t unit, int which){
@@ -211,13 +220,13 @@ void b100_dboard_iface::set_gpio_debug(unit_t unit, int which){
//set the debug on and which debug selection
switch(unit){
case UNIT_RX:
- _iface->poke16(B100_REG_GPIO_RX_DBG, 0xffff);
- _iface->poke16(B100_REG_GPIO_RX_SEL, dbg_sels);
+ _wb_iface->poke16(B100_REG_GPIO_RX_DBG, 0xffff);
+ _wb_iface->poke16(B100_REG_GPIO_RX_SEL, dbg_sels);
return;
case UNIT_TX:
- _iface->poke16(B100_REG_GPIO_TX_DBG, 0xffff);
- _iface->poke16(B100_REG_GPIO_TX_SEL, dbg_sels);
+ _wb_iface->poke16(B100_REG_GPIO_TX_DBG, 0xffff);
+ _wb_iface->poke16(B100_REG_GPIO_TX_SEL, dbg_sels);
return;
}
}
@@ -244,7 +253,7 @@ void b100_dboard_iface::write_spi(
boost::uint32_t data,
size_t num_bits
){
- _iface->transact_spi(unit_to_otw_spi_dev(unit), config, data, num_bits, false /*no rb*/);
+ _spi_iface->transact_spi(unit_to_otw_spi_dev(unit), config, data, num_bits, false /*no rb*/);
}
boost::uint32_t b100_dboard_iface::read_write_spi(
@@ -253,18 +262,18 @@ boost::uint32_t b100_dboard_iface::read_write_spi(
boost::uint32_t data,
size_t num_bits
){
- return _iface->transact_spi(unit_to_otw_spi_dev(unit), config, data, num_bits, true /*rb*/);
+ return _spi_iface->transact_spi(unit_to_otw_spi_dev(unit), config, data, num_bits, true /*rb*/);
}
/***********************************************************************
* I2C
**********************************************************************/
void b100_dboard_iface::write_i2c(boost::uint8_t addr, const byte_vector_t &bytes){
- return _iface->write_i2c(addr, bytes);
+ return _i2c_iface->write_i2c(addr, bytes);
}
byte_vector_t b100_dboard_iface::read_i2c(boost::uint8_t addr, size_t num_bytes){
- return _iface->read_i2c(addr, num_bytes);
+ return _i2c_iface->read_i2c(addr, num_bytes);
}
/***********************************************************************
diff --git a/host/lib/usrp/b100/dboard_impl.cpp b/host/lib/usrp/b100/dboard_impl.cpp
deleted file mode 100644
index ba3776728..000000000
--- a/host/lib/usrp/b100/dboard_impl.cpp
+++ /dev/null
@@ -1,185 +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 "b100_impl.hpp"
-#include "b100_regs.hpp"
-#include <uhd/exception.hpp>
-#include <uhd/usrp/dboard_props.hpp>
-#include <uhd/usrp/subdev_props.hpp>
-#include <uhd/usrp/misc_utils.hpp>
-#include <boost/bind.hpp>
-#include "usrp_i2c_addr.h"
-
-using namespace uhd;
-using namespace uhd::usrp;
-
-/***********************************************************************
- * Dboard Initialization
- **********************************************************************/
-void b100_impl::dboard_init(void){
- //read the tx and rx dboard eeproms
- _rx_db_eeprom.load(*_iface, I2C_ADDR_RX_A);
- _tx_db_eeprom.load(*_iface, I2C_ADDR_TX_A);
- _gdb_eeprom.load(*_iface, I2C_ADDR_TX_A ^ 5);
-
- //create a new dboard interface and manager
- _dboard_iface = make_b100_dboard_iface(
- _iface, _clock_ctrl, _codec_ctrl
- );
- _dboard_manager = dboard_manager::make(
- _rx_db_eeprom.id,
- ((_gdb_eeprom.id == dboard_id_t::none())? _tx_db_eeprom : _gdb_eeprom).id,
- _dboard_iface
- );
-
- //setup the dboard proxies
- _rx_dboard_proxy = wax_obj_proxy::make(
- boost::bind(&b100_impl::rx_dboard_get, this, _1, _2),
- boost::bind(&b100_impl::rx_dboard_set, this, _1, _2)
- );
- _tx_dboard_proxy = wax_obj_proxy::make(
- boost::bind(&b100_impl::tx_dboard_get, this, _1, _2),
- boost::bind(&b100_impl::tx_dboard_set, this, _1, _2)
- );
-}
-
-/***********************************************************************
- * RX Dboard Get
- **********************************************************************/
-void b100_impl::rx_dboard_get(const wax::obj &key_, wax::obj &val){
- named_prop_t key = named_prop_t::extract(key_);
-
- //handle the get request conditioned on the key
- switch(key.as<dboard_prop_t>()){
- case DBOARD_PROP_NAME:
- val = std::string("b100 dboard (rx unit)");
- return;
-
- case DBOARD_PROP_SUBDEV:
- val = _dboard_manager->get_rx_subdev(key.name);
- return;
-
- case DBOARD_PROP_SUBDEV_NAMES:
- val = _dboard_manager->get_rx_subdev_names();
- return;
-
- case DBOARD_PROP_DBOARD_EEPROM:
- val = _rx_db_eeprom;
- return;
-
- case DBOARD_PROP_DBOARD_IFACE:
- val = _dboard_iface;
- return;
-
- case DBOARD_PROP_CODEC:
- val = _rx_codec_proxy->get_link();
- return;
-
- case DBOARD_PROP_GAIN_GROUP:
- val = make_gain_group(
- _rx_db_eeprom.id,
- _dboard_manager->get_rx_subdev(key.name),
- _rx_codec_proxy->get_link(),
- GAIN_GROUP_POLICY_RX
- );
- return;
-
- default: UHD_THROW_PROP_GET_ERROR();
- }
-}
-
-/***********************************************************************
- * RX Dboard Set
- **********************************************************************/
-void b100_impl::rx_dboard_set(const wax::obj &key, const wax::obj &val){
- switch(key.as<dboard_prop_t>()){
- case DBOARD_PROP_DBOARD_EEPROM:
- _rx_db_eeprom = val.as<dboard_eeprom_t>();
- _rx_db_eeprom.store(*_iface, I2C_ADDR_RX_A);
- return;
-
- default: UHD_THROW_PROP_SET_ERROR();
- }
-}
-
-/***********************************************************************
- * TX Dboard Get
- **********************************************************************/
-void b100_impl::tx_dboard_get(const wax::obj &key_, wax::obj &val){
- named_prop_t key = named_prop_t::extract(key_);
-
- //handle the get request conditioned on the key
- switch(key.as<dboard_prop_t>()){
- case DBOARD_PROP_NAME:
- val = std::string("b100 dboard (tx unit)");
- return;
-
- case DBOARD_PROP_SUBDEV:
- val = _dboard_manager->get_tx_subdev(key.name);
- return;
-
- case DBOARD_PROP_SUBDEV_NAMES:
- val = _dboard_manager->get_tx_subdev_names();
- return;
-
- case DBOARD_PROP_DBOARD_EEPROM:
- val = _tx_db_eeprom;
- return;
-
- case DBOARD_PROP_GBOARD_EEPROM:
- val = _gdb_eeprom;
- return;
-
- case DBOARD_PROP_DBOARD_IFACE:
- val = _dboard_iface;
- return;
-
- case DBOARD_PROP_CODEC:
- val = _tx_codec_proxy->get_link();
- return;
-
- case DBOARD_PROP_GAIN_GROUP:
- val = make_gain_group(
- _tx_db_eeprom.id,
- _dboard_manager->get_tx_subdev(key.name),
- _tx_codec_proxy->get_link(),
- GAIN_GROUP_POLICY_TX
- );
- return;
-
- default: UHD_THROW_PROP_GET_ERROR();
- }
-}
-
-/***********************************************************************
- * TX Dboard Set
- **********************************************************************/
-void b100_impl::tx_dboard_set(const wax::obj &key, const wax::obj &val){
- switch(key.as<dboard_prop_t>()){
- case DBOARD_PROP_DBOARD_EEPROM:
- _tx_db_eeprom = val.as<dboard_eeprom_t>();
- _tx_db_eeprom.store(*_iface, I2C_ADDR_TX_A);
- return;
-
- case DBOARD_PROP_GBOARD_EEPROM:
- _gdb_eeprom = val.as<dboard_eeprom_t>();
- _gdb_eeprom.store(*_iface, I2C_ADDR_TX_A ^ 5);
- return;
-
- default: UHD_THROW_PROP_SET_ERROR();
- }
-}
diff --git a/host/lib/usrp/b100/dsp_impl.cpp b/host/lib/usrp/b100/dsp_impl.cpp
deleted file mode 100644
index c1bf6bedd..000000000
--- a/host/lib/usrp/b100/dsp_impl.cpp
+++ /dev/null
@@ -1,189 +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 "b100_impl.hpp"
-#include "b100_regs.hpp"
-#include <uhd/usrp/dsp_utils.hpp>
-#include <uhd/usrp/dsp_props.hpp>
-#include <boost/math/special_functions/round.hpp>
-#include <boost/bind.hpp>
-
-#define rint boost::math::iround
-
-using namespace uhd;
-using namespace uhd::usrp;
-
-static const double MASTER_CLOCK_RATE = 64e6; //TODO get from clock control
-
-/***********************************************************************
- * RX DDC Initialization
- **********************************************************************/
-void b100_impl::rx_ddc_init(void){
- _rx_ddc_proxy = wax_obj_proxy::make(
- boost::bind(&b100_impl::rx_ddc_get, this, _1, _2),
- boost::bind(&b100_impl::rx_ddc_set, this, _1, _2)
- );
-
- //initial config and update
- rx_ddc_set(DSP_PROP_FREQ_SHIFT, double(0));
- rx_ddc_set(DSP_PROP_HOST_RATE, double(16e6));
-}
-
-/***********************************************************************
- * RX DDC Get
- **********************************************************************/
-void b100_impl::rx_ddc_get(const wax::obj &key_, wax::obj &val){
- named_prop_t key = named_prop_t::extract(key_);
-
- switch(key.as<dsp_prop_t>()){
- case DSP_PROP_NAME:
- val = std::string("USRP-B100 RX DSP");
- return;
-
- case DSP_PROP_OTHERS:
- val = prop_names_t(); //empty
- return;
-
- case DSP_PROP_FREQ_SHIFT:
- val = _ddc_freq;
- return;
-
- case DSP_PROP_CODEC_RATE:
- val = _clock_ctrl->get_fpga_clock_rate();
- return;
-
- case DSP_PROP_HOST_RATE:
- val = _clock_ctrl->get_fpga_clock_rate()/_ddc_decim;
- return;
-
- default: UHD_THROW_PROP_GET_ERROR();
- }
-}
-
-/***********************************************************************
- * RX DDC Set
- **********************************************************************/
-void b100_impl::rx_ddc_set(const wax::obj &key_, const wax::obj &val){
- named_prop_t key = named_prop_t::extract(key_);
-
- switch(key.as<dsp_prop_t>()){
- case DSP_PROP_STREAM_CMD:
- issue_stream_cmd(val.as<stream_cmd_t>());
- return;
-
- case DSP_PROP_FREQ_SHIFT:{
- double new_freq = val.as<double>();
- _iface->poke32(B100_REG_DSP_RX_FREQ,
- dsp_type1::calc_cordic_word_and_update(new_freq, _clock_ctrl->get_fpga_clock_rate())
- );
- _ddc_freq = new_freq; //shadow
- }
- return;
-
- case DSP_PROP_HOST_RATE:{
- //set the decimation
- _ddc_decim = rint(_clock_ctrl->get_fpga_clock_rate()/val.as<double>());
- _iface->poke32(B100_REG_DSP_RX_DECIM_RATE, dsp_type1::calc_cic_filter_word(_ddc_decim));
-
- //set the scaling
- static const boost::int16_t default_rx_scale_iq = 1024;
- _iface->poke32(B100_REG_DSP_RX_SCALE_IQ,
- dsp_type1::calc_iq_scale_word(default_rx_scale_iq, default_rx_scale_iq)
- );
- }
- return;
-
- default: UHD_THROW_PROP_SET_ERROR();
- }
-}
-
-/***********************************************************************
- * TX DUC Initialization
- **********************************************************************/
-void b100_impl::tx_duc_init(void){
- _tx_duc_proxy = wax_obj_proxy::make(
- boost::bind(&b100_impl::tx_duc_get, this, _1, _2),
- boost::bind(&b100_impl::tx_duc_set, this, _1, _2)
- );
-
- //initial config and update
- tx_duc_set(DSP_PROP_FREQ_SHIFT, double(0));
- tx_duc_set(DSP_PROP_HOST_RATE, double(16e6));
-}
-
-/***********************************************************************
- * TX DUC Get
- **********************************************************************/
-void b100_impl::tx_duc_get(const wax::obj &key_, wax::obj &val){
- named_prop_t key = named_prop_t::extract(key_);
-
- switch(key.as<dsp_prop_t>()){
- case DSP_PROP_NAME:
- val = std::string("USRP-B100 TX DSP");
- return;
-
- case DSP_PROP_OTHERS:
- val = prop_names_t(); //empty
- return;
-
- case DSP_PROP_FREQ_SHIFT:
- val = _duc_freq;
- return;
-
- case DSP_PROP_CODEC_RATE:
- val = _clock_ctrl->get_fpga_clock_rate();
- return;
-
- case DSP_PROP_HOST_RATE:
- val = _clock_ctrl->get_fpga_clock_rate()/_duc_interp;
- return;
-
- default: UHD_THROW_PROP_GET_ERROR();
- }
-}
-
-/***********************************************************************
- * TX DUC Set
- **********************************************************************/
-void b100_impl::tx_duc_set(const wax::obj &key_, const wax::obj &val){
- named_prop_t key = named_prop_t::extract(key_);
-
- switch(key.as<dsp_prop_t>()){
-
- case DSP_PROP_FREQ_SHIFT:{
- double new_freq = val.as<double>();
- _iface->poke32(B100_REG_DSP_TX_FREQ,
- dsp_type1::calc_cordic_word_and_update(new_freq, _clock_ctrl->get_fpga_clock_rate())
- );
- _duc_freq = new_freq; //shadow
- }
- return;
-
- case DSP_PROP_HOST_RATE:{
- _duc_interp = rint(_clock_ctrl->get_fpga_clock_rate()/val.as<double>());
-
- //set the interpolation
- _iface->poke32(B100_REG_DSP_TX_INTERP_RATE, dsp_type1::calc_cic_filter_word(_duc_interp));
-
- //set the scaling
- _iface->poke32(B100_REG_DSP_TX_SCALE_IQ, dsp_type1::calc_iq_scale_word(_duc_interp));
- }
- return;
-
- default: UHD_THROW_PROP_SET_ERROR();
- }
-}
diff --git a/host/lib/usrp/b100/io_impl.cpp b/host/lib/usrp/b100/io_impl.cpp
index 3978bea75..d841188c0 100644
--- a/host/lib/usrp/b100/io_impl.cpp
+++ b/host/lib/usrp/b100/io_impl.cpp
@@ -1,5 +1,5 @@
//
-// Copyright 2010 Ettus Research LLC
+// Copyright 2011 Ettus Research LLC
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -15,132 +15,192 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
+#include "recv_packet_demuxer.hpp"
+#include "validate_subdev_spec.hpp"
#include "../../transport/super_recv_packet_handler.hpp"
#include "../../transport/super_send_packet_handler.hpp"
#include "usrp_commands.h"
#include "b100_impl.hpp"
#include "b100_regs.hpp"
-#include <uhd/usrp/dsp_utils.hpp>
-#include <uhd/usrp/dsp_props.hpp>
#include <uhd/utils/thread_priority.hpp>
#include <uhd/transport/bounded_buffer.hpp>
#include <boost/bind.hpp>
#include <boost/format.hpp>
-#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/thread.hpp>
#include <uhd/utils/msg.hpp>
#include <uhd/utils/log.hpp>
-#include <iostream>
using namespace uhd;
using namespace uhd::usrp;
using namespace uhd::transport;
-namespace asio = boost::asio;
/***********************************************************************
* IO Implementation Details
**********************************************************************/
struct b100_impl::io_impl{
- io_impl(zero_copy_if::sptr data_transport):
- data_transport(data_transport)
- {
- /* NOP */
- }
-
- ~io_impl(void){
- //drain the rx buffs
- //while(data_transport->get_recv_buff().get() != NULL){
- /* NOP */
- //}
- }
-
- zero_copy_if::sptr &data_transport;
+ io_impl(void):
+ async_msg_fifo(100/*messages deep*/)
+ { /* NOP */ }
+ zero_copy_if::sptr data_transport;
+ bounded_buffer<async_metadata_t> async_msg_fifo;
+ recv_packet_demuxer::sptr demuxer;
sph::recv_packet_handler recv_handler;
sph::send_packet_handler send_handler;
- bool continuous_streaming;
};
/***********************************************************************
* Initialize internals within this file
**********************************************************************/
void b100_impl::io_init(void){
- _recv_otw_type.width = 16;
- _recv_otw_type.shift = 0;
- _recv_otw_type.byteorder = otw_type_t::BO_LITTLE_ENDIAN;
-
- _send_otw_type.width = 16;
- _send_otw_type.shift = 0;
- _send_otw_type.byteorder = otw_type_t::BO_LITTLE_ENDIAN;
-
- _iface->reset_gpif(6);
-
- //reset state machines
- _iface->poke32(B100_REG_CTRL_TX_CLEAR_UNDERRUN, 0);
- _iface->poke32(B100_REG_CTRL_RX_CLEAR_OVERRUN, 0);
-
- _io_impl = UHD_PIMPL_MAKE(io_impl, (_data_transport));
-
- //setup rx data path
- _iface->poke32(B100_REG_CTRL_RX_NSAMPS_PER_PKT, get_max_recv_samps_per_packet());
- UHD_LOGV(always) << "IO: Using " << get_max_recv_samps_per_packet() << " samples per packet" << std::endl;
- _iface->poke32(B100_REG_CTRL_RX_NCHANNELS, 1);
- _iface->poke32(B100_REG_CTRL_RX_VRT_HEADER, 0
- | (0x1 << 28) //if data with stream id
- | (0x1 << 26) //has trailer
- | (0x3 << 22) //integer time other
- | (0x1 << 20) //fractional time sample count
- );
- _iface->poke32(B100_REG_CTRL_RX_VRT_TRAILER, 0);
- //set the streamid to reset the seq num
- _iface->poke32(B100_REG_CTRL_TX_REPORT_SID, 0);
- //setup the tx policy
- _iface->poke32(B100_REG_CTRL_TX_POLICY, B100_FLAG_CTRL_TX_POLICY_NEXT_PACKET);
-
+ //setup rx otw type
+ _rx_otw_type.width = 16;
+ _rx_otw_type.shift = 0;
+ _rx_otw_type.byteorder = uhd::otw_type_t::BO_LITTLE_ENDIAN;
+
+ //setup tx otw type
+ _tx_otw_type.width = 16;
+ _tx_otw_type.shift = 0;
+ _tx_otw_type.byteorder = uhd::otw_type_t::BO_LITTLE_ENDIAN;
+
+ //TODO best place to put this?
+ this->reset_gpif(6);
+
//set the expected packet size in USB frames
- _iface->poke32(B100_REG_MISC_RX_LEN, 4);
+ _fpga_ctrl->poke32(B100_REG_MISC_RX_LEN, 4);
+
+ //create new io impl
+ _io_impl = UHD_PIMPL_MAKE(io_impl, ());
+ _io_impl->demuxer = recv_packet_demuxer::make(_data_transport, _rx_dsps.size(), B100_RX_SID_BASE);
+
+ //now its safe to register the async callback
+ _fpga_ctrl->set_async_cb(boost::bind(&b100_impl::handle_async_message, this, _1));
+
+ //init some handler stuff
+ _io_impl->recv_handler.set_vrt_unpacker(&vrt::if_hdr_unpack_le);
+ _io_impl->recv_handler.set_converter(_rx_otw_type);
+ _io_impl->send_handler.set_vrt_packer(&vrt::if_hdr_pack_le);
+ _io_impl->send_handler.set_converter(_tx_otw_type);
+ _io_impl->send_handler.set_max_samples_per_packet(get_max_send_samps_per_packet());
+}
+
+void b100_impl::handle_async_message(managed_recv_buffer::sptr rbuf){
+ vrt::if_packet_info_t if_packet_info;
+ if_packet_info.num_packet_words32 = rbuf->size()/sizeof(boost::uint32_t);
+ const boost::uint32_t *vrt_hdr = rbuf->cast<const boost::uint32_t *>();
+ try{
+ vrt::if_hdr_unpack_le(vrt_hdr, if_packet_info);
+ }
+ catch(const std::exception &e){
+ UHD_MSG(error) << "Error (handle_async_message): " << e.what() << std::endl;
+ }
- update_transport_channel_mapping();
+ if (if_packet_info.sid == B100_TX_ASYNC_SID 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 = 0;
+ 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), _clock_ctrl->get_fpga_clock_rate()
+ );
+ metadata.event_code = async_metadata_t::event_code_t(sph::get_context_code(vrt_hdr, if_packet_info));
+ _io_impl->async_msg_fifo.push_with_pop_on_full(metadata);
+ if (metadata.event_code &
+ ( async_metadata_t::EVENT_CODE_UNDERFLOW
+ | async_metadata_t::EVENT_CODE_UNDERFLOW_IN_PACKET)
+ ) UHD_MSG(fastpath) << "U";
+ else if (metadata.event_code &
+ ( async_metadata_t::EVENT_CODE_SEQ_ERROR
+ | async_metadata_t::EVENT_CODE_SEQ_ERROR_IN_BURST)
+ ) UHD_MSG(fastpath) << "S";
+ }
+ else UHD_MSG(error) << "Unknown async packet" << std::endl;
}
-void b100_impl::update_transport_channel_mapping(void){
- if (_io_impl.get() == NULL) return; //not inited yet
+void b100_impl::update_tick_rate(const double rate){
+ boost::mutex::scoped_lock recv_lock = _io_impl->recv_handler.get_scoped_lock();
+ _io_impl->recv_handler.set_tick_rate(rate);
+ boost::mutex::scoped_lock send_lock = _io_impl->send_handler.get_scoped_lock();
+ _io_impl->send_handler.set_tick_rate(rate);
+}
- //set all of the relevant properties on the handler
+void b100_impl::update_rx_samp_rate(const double rate){
boost::mutex::scoped_lock recv_lock = _io_impl->recv_handler.get_scoped_lock();
- _io_impl->recv_handler.resize(_rx_subdev_spec.size());
- _io_impl->recv_handler.set_vrt_unpacker(&vrt::if_hdr_unpack_le);
- _io_impl->recv_handler.set_tick_rate(_clock_ctrl->get_fpga_clock_rate());
- _io_impl->recv_handler.set_samp_rate(_rx_ddc_proxy->get_link()[DSP_PROP_HOST_RATE].as<double>());
- for (size_t chan = 0; chan < _io_impl->recv_handler.size(); chan++){
- _io_impl->recv_handler.set_xport_chan_get_buff(chan, boost::bind(
- &uhd::transport::zero_copy_if::get_recv_buff, _io_impl->data_transport, _1
- ));
- _io_impl->recv_handler.set_overflow_handler(chan, boost::bind(
- &b100_impl::handle_overrun, this, chan
+ _io_impl->recv_handler.set_samp_rate(rate);
+ const double adj = _rx_dsps.front()->get_scaling_adjustment();
+ _io_impl->recv_handler.set_scale_factor(adj/32767.);
+}
+
+void b100_impl::update_tx_samp_rate(const double rate){
+ boost::mutex::scoped_lock send_lock = _io_impl->send_handler.get_scoped_lock();
+ _io_impl->send_handler.set_samp_rate(rate);
+}
+
+void b100_impl::update_rx_subdev_spec(const uhd::usrp::subdev_spec_t &spec){
+ boost::mutex::scoped_lock recv_lock = _io_impl->recv_handler.get_scoped_lock();
+ property_tree::path_type root = "/mboards/0/dboards";
+
+ //sanity checking
+ validate_subdev_spec(_tree, spec, "rx");
+
+ //setup mux for this spec
+ bool fe_swapped = false;
+ for (size_t i = 0; i < spec.size(); i++){
+ const std::string conn = _tree->access<std::string>(root / spec[i].db_name / "rx_frontends" / spec[i].sd_name / "connection").get();
+ if (i == 0 and (conn == "QI" or conn == "Q")) fe_swapped = true;
+ _rx_dsps[i]->set_mux(conn, fe_swapped);
+ }
+ _rx_fe->set_mux(fe_swapped);
+
+ //resize for the new occupancy
+ _io_impl->recv_handler.resize(spec.size());
+
+ //bind new callbacks for the handler
+ for (size_t i = 0; i < _io_impl->recv_handler.size(); i++){
+ _rx_dsps[i]->set_nsamps_per_packet(get_max_recv_samps_per_packet()); //seems to be a good place to set this
+ _io_impl->recv_handler.set_xport_chan_get_buff(i, boost::bind(
+ &recv_packet_demuxer::get_recv_buff, _io_impl->demuxer, i, _1
));
+ _io_impl->recv_handler.set_overflow_handler(i, boost::bind(&rx_dsp_core_200::handle_overflow, _rx_dsps[i]));
}
- _io_impl->recv_handler.set_converter(_recv_otw_type);
+}
- //set all of the relevant properties on the handler
+void b100_impl::update_tx_subdev_spec(const uhd::usrp::subdev_spec_t &spec){
boost::mutex::scoped_lock send_lock = _io_impl->send_handler.get_scoped_lock();
- _io_impl->send_handler.resize(_tx_subdev_spec.size());
- _io_impl->send_handler.set_vrt_packer(&vrt::if_hdr_pack_le);
- _io_impl->send_handler.set_tick_rate(_clock_ctrl->get_fpga_clock_rate());
- _io_impl->send_handler.set_samp_rate(_tx_duc_proxy->get_link()[DSP_PROP_HOST_RATE].as<double>());
- for (size_t chan = 0; chan < _io_impl->send_handler.size(); chan++){
- _io_impl->send_handler.set_xport_chan_get_buff(chan, boost::bind(
- &uhd::transport::zero_copy_if::get_send_buff, _io_impl->data_transport, _1
+ property_tree::path_type root = "/mboards/0/dboards";
+
+ //sanity checking
+ validate_subdev_spec(_tree, spec, "tx");
+
+ //set the mux for this spec
+ const std::string conn = _tree->access<std::string>(root / spec[0].db_name / "tx_frontends" / spec[0].sd_name / "connection").get();
+ _tx_fe->set_mux(conn);
+
+ //resize for the new occupancy
+ _io_impl->send_handler.resize(spec.size());
+
+ //bind new callbacks for the handler
+ for (size_t i = 0; i < _io_impl->send_handler.size(); i++){
+ _io_impl->send_handler.set_xport_chan_get_buff(i, boost::bind(
+ &zero_copy_if::get_send_buff, _data_transport, _1
));
}
- _io_impl->send_handler.set_converter(_send_otw_type);
- _io_impl->send_handler.set_max_samples_per_packet(get_max_send_samps_per_packet());
}
/***********************************************************************
- * Data send + helper functions
+ * Async Data
+ **********************************************************************/
+bool b100_impl::recv_async_msg(
+ async_metadata_t &async_metadata, double timeout
+){
+ boost::this_thread::disable_interruption di; //disable because the wait can throw
+ return _io_impl->async_msg_fifo.pop_with_timed_wait(async_metadata, timeout);
+}
+
+/***********************************************************************
+ * Send Data
**********************************************************************/
size_t b100_impl::get_max_send_samps_per_packet(void) const {
static const size_t hdr_size = 0
@@ -148,14 +208,14 @@ size_t b100_impl::get_max_send_samps_per_packet(void) const {
- sizeof(vrt::if_packet_info_t().cid) //no class id ever used
;
static const size_t bpp = 2048 - hdr_size;
- return bpp / _send_otw_type.get_sample_size();
+ return bpp / _tx_otw_type.get_sample_size();
}
size_t b100_impl::send(
const send_buffs_type &buffs, size_t nsamps_per_buff,
const tx_metadata_t &metadata, const io_type_t &io_type,
send_mode_t send_mode, double timeout
-){
+){
return _io_impl->send_handler.send(
buffs, nsamps_per_buff,
metadata, io_type,
@@ -164,9 +224,8 @@ size_t b100_impl::send(
}
/***********************************************************************
- * Data recv + helper functions
+ * Receive Data
**********************************************************************/
-
size_t b100_impl::get_max_recv_samps_per_packet(void) const {
static const size_t hdr_size = 0
+ vrt::max_if_hdr_words32*sizeof(boost::uint32_t)
@@ -174,7 +233,7 @@ size_t b100_impl::get_max_recv_samps_per_packet(void) const {
- sizeof(vrt::if_packet_info_t().cid) //no class id ever used
;
size_t bpp = 2048 - hdr_size; //limited by FPGA pkt buffer size
- return bpp/_recv_otw_type.get_sample_size();
+ return bpp/_rx_otw_type.get_sample_size();
}
size_t b100_impl::recv(
@@ -188,23 +247,3 @@ size_t b100_impl::recv(
recv_mode, timeout
);
}
-
-void b100_impl::issue_stream_cmd(const stream_cmd_t &stream_cmd)
-{
- _io_impl->continuous_streaming = (stream_cmd.stream_mode == stream_cmd_t::STREAM_MODE_START_CONTINUOUS);
- _iface->poke32(B100_REG_CTRL_RX_STREAM_CMD, dsp_type1::calc_stream_cmd_word(stream_cmd));
- _iface->poke32(B100_REG_CTRL_RX_TIME_SECS, boost::uint32_t(stream_cmd.time_spec.get_full_secs()));
- _iface->poke32(B100_REG_CTRL_RX_TIME_TICKS, stream_cmd.time_spec.get_tick_count(_clock_ctrl->get_fpga_clock_rate()));
-
- if (stream_cmd.stream_mode == stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS) {
- while(_io_impl->data_transport->get_recv_buff().get() != NULL){
- /* NOP */
- }
- }
-}
-
-void b100_impl::handle_overrun(size_t){
- if (_io_impl->continuous_streaming){
- this->issue_stream_cmd(stream_cmd_t::STREAM_MODE_START_CONTINUOUS);
- }
-}
diff --git a/host/lib/usrp/b100/mboard_impl.cpp b/host/lib/usrp/b100/mboard_impl.cpp
deleted file mode 100644
index c651ff2a2..000000000
--- a/host/lib/usrp/b100/mboard_impl.cpp
+++ /dev/null
@@ -1,246 +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 "b100_impl.hpp"
-#include "usrp_commands.h"
-#include "fpga_regs_standard.h"
-#include "fpga_regs_common.h"
-#include "b100_regs.hpp"
-#include "usrp_i2c_addr.h"
-#include <uhd/usrp/misc_utils.hpp>
-#include <uhd/usrp/mboard_props.hpp>
-#include <uhd/usrp/dboard_props.hpp>
-#include <uhd/usrp/subdev_props.hpp>
-#include <uhd/utils/msg.hpp>
-#include <uhd/exception.hpp>
-#include <uhd/utils/images.hpp>
-#include <boost/assign/list_of.hpp>
-#include <boost/foreach.hpp>
-#include <boost/bind.hpp>
-#include <boost/thread/thread.hpp>
-#include <uhd/usrp/dsp_utils.hpp>
-
-using namespace uhd;
-using namespace uhd::usrp;
-
-static const bool b100_mboard_verbose = true;
-
-/***********************************************************************
- * Mboard Initialization
- **********************************************************************/
-void b100_impl::mboard_init(void)
-{
- _mboard_proxy = wax_obj_proxy::make(
- boost::bind(&b100_impl::mboard_get, this, _1, _2),
- boost::bind(&b100_impl::mboard_set, this, _1, _2));
-
- //set the ticks per seconds into the vita time control
- _iface->poke32(B100_REG_TIME64_TPS,
- boost::uint32_t(_clock_ctrl->get_fpga_clock_rate())
- );
-
- //init the clock config
- _clock_config = clock_config_t::internal();
- update_clock_config();
-}
-
-void b100_impl::update_clock_config(void){
- boost::uint32_t pps_flags = 0;
-
- //translate pps polarity enums
- switch(_clock_config.pps_polarity){
- case clock_config_t::PPS_POS: pps_flags |= B100_FLAG_TIME64_PPS_POSEDGE; break;
- case clock_config_t::PPS_NEG: pps_flags |= B100_FLAG_TIME64_PPS_NEGEDGE; break;
- default: throw uhd::runtime_error("unhandled clock configuration pps polarity");
- }
-
- //set the pps flags
- _iface->poke32(B100_REG_TIME64_FLAGS, pps_flags);
-
- //clock source ref 10mhz
- switch(_clock_config.ref_source){
- case clock_config_t::REF_AUTO: _clock_ctrl->use_auto_ref(); break;
- case clock_config_t::REF_INT: _clock_ctrl->use_internal_ref(); break;
- case clock_config_t::REF_SMA: _clock_ctrl->use_auto_ref(); break;
- default: throw uhd::runtime_error("unhandled clock configuration ref source");
- }
-}
-
-/***********************************************************************
- * Mboard Get
- **********************************************************************/
-void b100_impl::mboard_get(const wax::obj &key_, wax::obj &val){
- named_prop_t key = named_prop_t::extract(key_);
-
- //handle the get request conditioned on the key
- switch(key.as<mboard_prop_t>()){
- case MBOARD_PROP_NAME:
- val = std::string("USRP-B100 mboard");
- return;
-
- case MBOARD_PROP_OTHERS:
- val = prop_names_t();
- return;
-
- case MBOARD_PROP_RX_DBOARD:
- UHD_ASSERT_THROW(key.name == "");
- val = _rx_dboard_proxy->get_link();
- return;
-
- case MBOARD_PROP_RX_DBOARD_NAMES:
- val = prop_names_t(1, ""); //vector of size 1 with empty string
- return;
-
- case MBOARD_PROP_TX_DBOARD:
- UHD_ASSERT_THROW(key.name == "");
- val = _tx_dboard_proxy->get_link();
- return;
-
- case MBOARD_PROP_TX_DBOARD_NAMES:
- val = prop_names_t(1, ""); //vector of size 1 with empty string
- return;
-
- case MBOARD_PROP_RX_DSP:
- UHD_ASSERT_THROW(key.name == "");
- val = _rx_ddc_proxy->get_link();
- return;
-
- case MBOARD_PROP_RX_DSP_NAMES:
- val = prop_names_t(1, "");
- return;
-
- case MBOARD_PROP_TX_DSP:
- UHD_ASSERT_THROW(key.name == "");
- val = _tx_duc_proxy->get_link();
- return;
-
- case MBOARD_PROP_TX_DSP_NAMES:
- val = prop_names_t(1, "");
- return;
-
- case MBOARD_PROP_CLOCK_CONFIG:
- val = _clock_config;
- return;
-
- case MBOARD_PROP_RX_SUBDEV_SPEC:
- val = _rx_subdev_spec;
- return;
-
- case MBOARD_PROP_TX_SUBDEV_SPEC:
- val = _tx_subdev_spec;
- return;
-
- case MBOARD_PROP_EEPROM_MAP:
- val = _iface->mb_eeprom;
- return;
-
- case MBOARD_PROP_TIME_NOW:while(true){
- uint32_t secs = _iface->peek32(B100_REG_RB_TIME_NOW_SECS);
- uint32_t ticks = _iface->peek32(B100_REG_RB_TIME_NOW_TICKS);
- if (secs != _iface->peek32(B100_REG_RB_TIME_NOW_SECS)) continue;
- val = time_spec_t(secs, ticks, _clock_ctrl->get_fpga_clock_rate());
- return;
- }
-
- case MBOARD_PROP_TIME_PPS: while(true){
- uint32_t secs = _iface->peek32(B100_REG_RB_TIME_PPS_SECS);
- uint32_t ticks = _iface->peek32(B100_REG_RB_TIME_PPS_TICKS);
- if (secs != _iface->peek32(B100_REG_RB_TIME_PPS_SECS)) continue;
- val = time_spec_t(secs, ticks, _clock_ctrl->get_fpga_clock_rate());
- return;
- }
-
- case MBOARD_PROP_CLOCK_RATE:
- val = _clock_ctrl->get_fpga_clock_rate();
- return;
-
- default: UHD_THROW_PROP_GET_ERROR();
- }
-}
-
-/***********************************************************************
- * Mboard Set
- **********************************************************************/
-void b100_impl::mboard_set(const wax::obj &key, const wax::obj &val)
-{
- if(key.type() == typeid(std::string)) {
- if(key.as<std::string>() == "load_eeprom") {
- std::string b100_eeprom_image = val.as<std::string>();
- UHD_MSG(status) << "B100 EEPROM image: " << b100_eeprom_image << std::endl;
- _fx2_ctrl->usrp_load_eeprom(val.as<std::string>());
- }
- return;
- }
-
- //handle the get request conditioned on the key
- switch(key.as<mboard_prop_t>()){
- case MBOARD_PROP_TIME_NOW:
- case MBOARD_PROP_TIME_PPS:{
- time_spec_t time_spec = val.as<time_spec_t>();
- _iface->poke32(B100_REG_TIME64_TICKS, time_spec.get_tick_count(_clock_ctrl->get_fpga_clock_rate()));
- boost::uint32_t imm_flags = (key.as<mboard_prop_t>() == MBOARD_PROP_TIME_NOW)? 1 : 0;
- _iface->poke32(B100_REG_TIME64_IMM, imm_flags);
- _iface->poke32(B100_REG_TIME64_SECS, boost::uint32_t(time_spec.get_full_secs()));
- }
- return;
-
- case MBOARD_PROP_RX_SUBDEV_SPEC:
- _rx_subdev_spec = val.as<subdev_spec_t>();
- verify_rx_subdev_spec(_rx_subdev_spec, _mboard_proxy->get_link());
- UHD_ASSERT_THROW(_rx_subdev_spec.size() == 1);
- //set the mux
- _iface->poke32(B100_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>();
- verify_tx_subdev_spec(_tx_subdev_spec, _mboard_proxy->get_link());
- UHD_ASSERT_THROW(_tx_subdev_spec.size() == 1);
- //set the mux and set the number of tx channels
- _iface->poke32(B100_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;
-
- case MBOARD_PROP_EEPROM_MAP:
- // Step1: commit the map, writing only those values set.
- // Step2: readback the entire eeprom map into the iface.
- val.as<mboard_eeprom_t>().commit(*_iface, mboard_eeprom_t::MAP_B000);
- _iface->mb_eeprom = mboard_eeprom_t(*_iface, mboard_eeprom_t::MAP_B000);
- return;
-
- case MBOARD_PROP_CLOCK_CONFIG:
- _clock_config = val.as<clock_config_t>();
- update_clock_config();
- return;
-
- case MBOARD_PROP_CLOCK_RATE:
- UHD_MSG(warning)
- << "You are setting the master clock rate from the API.\n"
- << "You may want to pass this into the device address as master_clock_rate=<rate>.\n"
- << "This way, the clock rate is guaranteed to be initialized first.\n"
- << "See the application notes for USRP-B100 for further instructions.\n"
- ;
- _clock_ctrl->set_fpga_clock_rate(val.as<double>());
- update_transport_channel_mapping();
- return;
-
- default: UHD_THROW_PROP_SET_ERROR();
- }
-}
diff --git a/host/lib/usrp/fx2/CMakeLists.txt b/host/lib/usrp/common/CMakeLists.txt
index 9d1e15e16..ec8b60fec 100644
--- a/host/lib/usrp/fx2/CMakeLists.txt
+++ b/host/lib/usrp/common/CMakeLists.txt
@@ -16,11 +16,19 @@
#
########################################################################
+# This file included, use CMake directory variables
+########################################################################
IF(ENABLE_USB)
INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/../firmware/fx2/common)
LIBUHD_APPEND_SOURCES(
${CMAKE_CURRENT_SOURCE_DIR}/fx2_ctrl.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/fx2_ctrl.hpp
)
ENDIF(ENABLE_USB)
+
+INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR})
+
+LIBUHD_APPEND_SOURCES(
+ ${CMAKE_CURRENT_SOURCE_DIR}/validate_subdev_spec.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/recv_packet_demuxer.cpp
+)
diff --git a/host/lib/usrp/fx2/fx2_ctrl.cpp b/host/lib/usrp/common/fx2_ctrl.cpp
index 06ca51c25..8f2206221 100644
--- a/host/lib/usrp/fx2/fx2_ctrl.cpp
+++ b/host/lib/usrp/common/fx2_ctrl.cpp
@@ -240,9 +240,9 @@ public:
while (not file.eof()) {
file.read((char *)buf, sizeof(buf));
- size_t n = file.gcount();
+ const std::streamsize n = file.gcount();
if(n == 0) continue;
- int ret = usrp_control_write(VRQ_FPGA_LOAD, 0, FL_XFER, buf, n);
+ int ret = usrp_control_write(VRQ_FPGA_LOAD, 0, FL_XFER, buf, boost::uint16_t(n));
if (ret < 0 or size_t(ret) != n) {
throw uhd::io_error("usrp_load_fpga: fpga load error");
}
@@ -262,11 +262,10 @@ public:
void usrp_load_eeprom(std::string filestring)
{
+ if (load_img_msg) UHD_MSG(status) << "Loading EEPROM image: " << filestring << "..." << std::flush;
const char *filename = filestring.c_str();
const boost::uint16_t i2c_addr = 0x50;
- //FIXME: verify types
- int len;
unsigned int addr;
unsigned char data[256];
unsigned char sendbuf[17];
@@ -279,7 +278,7 @@ public:
}
file.read((char *)data, 256);
- len = file.gcount();
+ std::streamsize len = file.gcount();
if(len == 256) {
throw uhd::io_error("usrp_load_eeprom: image size too large");
@@ -289,8 +288,8 @@ public:
addr = 0;
while(len > 0) {
sendbuf[0] = addr;
- memcpy(sendbuf+1, &data[addr], len > pagesize ? pagesize : len);
- int ret = usrp_i2c_write(i2c_addr, sendbuf, (len > pagesize ? pagesize : len)+1);
+ memcpy(sendbuf+1, &data[addr], len > pagesize ? pagesize : size_t(len));
+ int ret = usrp_i2c_write(i2c_addr, sendbuf, (len > pagesize ? pagesize : size_t(len))+1);
if (ret < 0) {
throw uhd::io_error("usrp_load_eeprom: usrp_i2c_write failed");
}
@@ -299,6 +298,7 @@ public:
boost::this_thread::sleep(boost::posix_time::milliseconds(100));
}
file.close();
+ if (load_img_msg) UHD_MSG(status) << " done" << std::endl;
}
@@ -409,6 +409,42 @@ public:
return usrp_control_read(VRQ_I2C_READ, i2c_addr, 0, buf, len);
}
+ static const bool iface_debug = false;
+ static const size_t max_i2c_data_bytes = 64;
+
+ void write_i2c(boost::uint8_t addr, const byte_vector_t &bytes)
+ {
+ UHD_ASSERT_THROW(bytes.size() < max_i2c_data_bytes);
+
+ unsigned char buff[max_i2c_data_bytes];
+ std::copy(bytes.begin(), bytes.end(), buff);
+
+ int ret = this->usrp_i2c_write(addr & 0xff,
+ buff,
+ bytes.size());
+
+ if (iface_debug && (ret < 0))
+ uhd::runtime_error("USRP: failed i2c write");
+ }
+
+ byte_vector_t read_i2c(boost::uint8_t addr, size_t num_bytes)
+ {
+ UHD_ASSERT_THROW(num_bytes < max_i2c_data_bytes);
+
+ unsigned char buff[max_i2c_data_bytes];
+ int ret = this->usrp_i2c_read(addr & 0xff,
+ buff,
+ num_bytes);
+
+ if (iface_debug && ((ret < 0) || (unsigned)ret < (num_bytes)))
+ uhd::runtime_error("USRP: failed i2c read");
+
+ byte_vector_t out_bytes;
+ for (size_t i = 0; i < num_bytes; i++)
+ out_bytes.push_back(buff[i]);
+
+ return out_bytes;
+ }
private:
diff --git a/host/lib/usrp/fx2/fx2_ctrl.hpp b/host/lib/usrp/common/fx2_ctrl.hpp
index 37fa09605..691d64275 100644
--- a/host/lib/usrp/fx2/fx2_ctrl.hpp
+++ b/host/lib/usrp/common/fx2_ctrl.hpp
@@ -15,16 +15,17 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
-#ifndef INCLUDED_USRP_CTRL_HPP
-#define INCLUDED_USRP_CTRL_HPP
+#ifndef INCLUDED_LIBUHD_USRP_COMMON_FX2_CTRL_HPP
+#define INCLUDED_LIBUHD_USRP_COMMON_FX2_CTRL_HPP
-#include <uhd/transport/usb_control.hpp>
+#include <uhd/transport/usb_control.hpp>
+#include <uhd/types/serial.hpp> //i2c iface
#include <boost/shared_ptr.hpp>
#include <boost/utility.hpp>
namespace uhd{ namespace usrp{
-class fx2_ctrl : boost::noncopyable{
+class fx2_ctrl : boost::noncopyable, public uhd::i2c_iface{
public:
typedef boost::shared_ptr<fx2_ctrl> sptr;
@@ -119,4 +120,4 @@ public:
}} //namespace uhd::usrp
-#endif /* INCLUDED_USRP_CTRL_HPP */
+#endif /* INCLUDED_LIBUHD_USRP_COMMON_FX2_CTRL_HPP */
diff --git a/host/lib/usrp/common/recv_packet_demuxer.cpp b/host/lib/usrp/common/recv_packet_demuxer.cpp
new file mode 100644
index 000000000..f2cfe3bb0
--- /dev/null
+++ b/host/lib/usrp/common/recv_packet_demuxer.cpp
@@ -0,0 +1,87 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// 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 "recv_packet_demuxer.hpp"
+#include <uhd/utils/msg.hpp>
+#include <uhd/utils/byteswap.hpp>
+#include <boost/thread/mutex.hpp>
+#include <queue>
+#include <deque>
+#include <vector>
+
+using namespace uhd;
+using namespace uhd::usrp;
+using namespace uhd::transport;
+
+static UHD_INLINE boost::uint32_t extract_sid(managed_recv_buffer::sptr &buff){
+ //ASSUME that the data is in little endian format
+ return uhd::wtohx(buff->cast<const boost::uint32_t *>()[1]);
+}
+
+class recv_packet_demuxer_impl : public uhd::usrp::recv_packet_demuxer{
+public:
+ recv_packet_demuxer_impl(
+ transport::zero_copy_if::sptr transport,
+ const size_t size,
+ const boost::uint32_t sid_base
+ ):
+ _transport(transport), _sid_base(sid_base), _queues(size)
+ {
+ /* NOP */
+ }
+
+ managed_recv_buffer::sptr get_recv_buff(const size_t index, const double timeout){
+ boost::mutex::scoped_lock lock(_mutex);
+ managed_recv_buffer::sptr buff;
+
+ //there is already an entry in the queue, so pop that
+ if (not _queues[index].wrapper.empty()){
+ std::swap(buff, _queues[index].wrapper.front());
+ _queues[index].wrapper.pop();
+ return buff;
+ }
+
+ while (true){
+ //otherwise call into the transport
+ buff = _transport->get_recv_buff(timeout);
+ if (buff.get() == NULL) return buff; //timeout
+
+ //check the stream id to know which channel
+ const size_t rx_index = extract_sid(buff) - _sid_base;
+ if (rx_index == index) return buff; //got expected message
+
+ //otherwise queue and try again
+ if (rx_index < _queues.size()) _queues[rx_index].wrapper.push(buff);
+ else UHD_MSG(error) << "Got a data packet with unknown SID " << extract_sid(buff) << std::endl;
+ }
+ }
+
+private:
+ transport::zero_copy_if::sptr _transport;
+ const boost::uint32_t _sid_base;
+ boost::mutex _mutex;
+ struct channel_guts_type{
+ channel_guts_type(void): wrapper(container){}
+ std::deque<managed_recv_buffer::sptr> container;
+ std::queue<managed_recv_buffer::sptr> wrapper;
+ };
+ std::vector<channel_guts_type> _queues;
+};
+
+recv_packet_demuxer::sptr recv_packet_demuxer::make(transport::zero_copy_if::sptr transport, const size_t size, const boost::uint32_t sid_base){
+ return sptr(new recv_packet_demuxer_impl(transport, size, sid_base));
+}
diff --git a/host/lib/usrp/common/recv_packet_demuxer.hpp b/host/lib/usrp/common/recv_packet_demuxer.hpp
new file mode 100644
index 000000000..fde756d27
--- /dev/null
+++ b/host/lib/usrp/common/recv_packet_demuxer.hpp
@@ -0,0 +1,41 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// 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_COMMON_RECV_PACKET_DEMUXER_HPP
+#define INCLUDED_LIBUHD_USRP_COMMON_RECV_PACKET_DEMUXER_HPP
+
+#include <uhd/config.hpp>
+#include <uhd/transport/zero_copy.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/cstdint.hpp>
+
+namespace uhd{ namespace usrp{
+
+ class recv_packet_demuxer{
+ public:
+ typedef boost::shared_ptr<recv_packet_demuxer> sptr;
+
+ //! Make a new demuxer from a transport and parameters
+ static sptr make(transport::zero_copy_if::sptr transport, const size_t size, const boost::uint32_t sid_base);
+
+ //! Get a buffer at the given index from the transport
+ virtual transport::managed_recv_buffer::sptr get_recv_buff(const size_t index, const double timeout) = 0;
+ };
+
+}} //namespace uhd::usrp
+
+#endif /* INCLUDED_LIBUHD_USRP_COMMON_RECV_PACKET_DEMUXER_HPP */
diff --git a/host/lib/usrp/common/validate_subdev_spec.cpp b/host/lib/usrp/common/validate_subdev_spec.cpp
new file mode 100644
index 000000000..fab40b204
--- /dev/null
+++ b/host/lib/usrp/common/validate_subdev_spec.cpp
@@ -0,0 +1,73 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// 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 "validate_subdev_spec.hpp"
+#include <uhd/exception.hpp>
+#include <uhd/utils/assert_has.hpp>
+#include <boost/foreach.hpp>
+#include <boost/format.hpp>
+
+using namespace uhd;
+using namespace uhd::usrp;
+
+namespace uhd{ namespace usrp{
+
+ static std::ostream& operator<< (std::ostream &out, const subdev_spec_pair_t &pair){
+ out << pair.db_name << ":" << pair.sd_name;
+ return out;
+ }
+
+}}
+
+void uhd::usrp::validate_subdev_spec(
+ property_tree::sptr tree,
+ const subdev_spec_t &spec,
+ const std::string &type,
+ const std::string &mb
+){
+ const size_t num_dsps = tree->list(str(boost::format("/mboards/%s/%s_dsps") % mb % type)).size();
+
+ //sanity checking on the length
+ if (spec.size() == 0) throw uhd::value_error(str(boost::format(
+ "Empty %s subdevice specification is not supported.\n"
+ ) % type));
+ if (spec.size() > num_dsps) throw uhd::value_error(str(boost::format(
+ "The subdevice specification \"%s\" is too long.\n"
+ "The user specified %u channels, but there are only %u %s dsps on mboard %s.\n"
+ ) % spec.to_string() % spec.size() % num_dsps % type % mb));
+
+ //make a list of all possible specs
+ subdev_spec_t all_specs;
+ BOOST_FOREACH(const std::string &db, tree->list(str(boost::format("/mboards/%s/dboards") % mb))){
+ BOOST_FOREACH(const std::string &sd, tree->list(str(boost::format("/mboards/%s/dboards/%s/%s_frontends") % mb % db % type))){
+ all_specs.push_back(subdev_spec_pair_t(db, sd));
+ }
+ }
+
+ //validate that the spec is possible
+ BOOST_FOREACH(const subdev_spec_pair_t &pair, spec){
+ uhd::assert_has(all_specs, pair, str(boost::format("%s subdevice specification on mboard %s") % type % mb));
+ }
+
+ //enable selected frontends, disable others
+ BOOST_FOREACH(const subdev_spec_pair_t &pair, all_specs){
+ const bool enb = uhd::has(spec, pair);
+ tree->access<bool>(str(boost::format(
+ "/mboards/%s/dboards/%s/%s_frontends/%s/enabled"
+ ) % mb % pair.db_name % type % pair.sd_name)).set(enb);
+ }
+}
diff --git a/host/include/uhd/usrp/device_props.hpp b/host/lib/usrp/common/validate_subdev_spec.hpp
index 3c8f7e225..7d9e2c309 100644
--- a/host/include/uhd/usrp/device_props.hpp
+++ b/host/lib/usrp/common/validate_subdev_spec.hpp
@@ -1,5 +1,5 @@
//
-// Copyright 2010-2011 Ettus Research LLC
+// Copyright 2011 Ettus Research LLC
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -15,25 +15,24 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
-#ifndef INCLUDED_UHD_USRP_DEVICE_PROPS_HPP
-#define INCLUDED_UHD_USRP_DEVICE_PROPS_HPP
+#ifndef INCLUDED_LIBUHD_USRP_COMMON_VALIDATE_SUBDEV_SPEC_HPP
+#define INCLUDED_LIBUHD_USRP_COMMON_VALIDATE_SUBDEV_SPEC_HPP
-#include <uhd/utils/props.hpp>
+#include <uhd/config.hpp>
+#include <uhd/usrp/subdev_spec.hpp>
+#include <uhd/property_tree.hpp>
+#include <string>
namespace uhd{ namespace usrp{
- /*!
- * Possible device properties:
- * In general, a device will have a single mboard.
- * In certain mimo applications, multiple boards
- * will be present in the interface for configuration.
- */
- enum device_prop_t{
- DEVICE_PROP_NAME, //ro, std::string
- DEVICE_PROP_MBOARD, //ro, wax::obj
- DEVICE_PROP_MBOARD_NAMES, //ro, prop_names_t
- };
+ //! Validate a subdev spec against a property tree
+ void validate_subdev_spec(
+ property_tree::sptr tree,
+ const subdev_spec_t &spec,
+ const std::string &type, //rx or tx
+ const std::string &mb = "0"
+ );
-}} //namespace
+}} //namespace uhd::usrp
-#endif /* INCLUDED_UHD_USRP_DEVICE_PROPS_HPP */
+#endif /* INCLUDED_LIBUHD_USRP_COMMON_VALIDATE_SUBDEV_SPEC_HPP */
diff --git a/host/lib/usrp/cores/CMakeLists.txt b/host/lib/usrp/cores/CMakeLists.txt
new file mode 100644
index 000000000..4476c9424
--- /dev/null
+++ b/host/lib/usrp/cores/CMakeLists.txt
@@ -0,0 +1,32 @@
+#
+# Copyright 2011 Ettus Research LLC
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# 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 included, use CMake directory variables
+########################################################################
+
+INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR})
+
+LIBUHD_APPEND_SOURCES(
+ ${CMAKE_CURRENT_SOURCE_DIR}/i2c_core_100.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/spi_core_100.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/time64_core_200.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/rx_dsp_core_200.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/tx_dsp_core_200.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/rx_frontend_core_200.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/tx_frontend_core_200.cpp
+)
diff --git a/host/lib/usrp/cores/i2c_core_100.cpp b/host/lib/usrp/cores/i2c_core_100.cpp
new file mode 100644
index 000000000..12352f108
--- /dev/null
+++ b/host/lib/usrp/cores/i2c_core_100.cpp
@@ -0,0 +1,138 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// 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 "i2c_core_100.hpp"
+#include <uhd/exception.hpp>
+#include <uhd/utils/msg.hpp>
+#include <boost/thread/thread.hpp> //sleep
+
+#define REG_I2C_PRESCALER_LO _base + 0
+#define REG_I2C_PRESCALER_HI _base + 2
+#define REG_I2C_CTRL _base + 4
+#define REG_I2C_DATA _base + 6
+#define REG_I2C_CMD_STATUS _base + 8
+
+//
+// STA, STO, RD, WR, and IACK bits are cleared automatically
+//
+
+#define I2C_CTRL_EN (1 << 7) // core enable
+#define I2C_CTRL_IE (1 << 6) // interrupt enable
+
+#define I2C_CMD_START (1 << 7) // generate (repeated) start condition
+#define I2C_CMD_STOP (1 << 6) // generate stop condition
+#define I2C_CMD_RD (1 << 5) // read from slave
+#define I2C_CMD_WR (1 << 4) // write to slave
+#define I2C_CMD_NACK (1 << 3) // when a rcvr, send ACK (ACK=0) or NACK (ACK=1)
+#define I2C_CMD_RSVD_2 (1 << 2) // reserved
+#define I2C_CMD_RSVD_1 (1 << 1) // reserved
+#define I2C_CMD_IACK (1 << 0) // set to clear pending interrupt
+
+#define I2C_ST_RXACK (1 << 7) // Received acknowledgement from slave (1 = NAK, 0 = ACK)
+#define I2C_ST_BUSY (1 << 6) // 1 after START signal detected; 0 after STOP signal detected
+#define I2C_ST_AL (1 << 5) // Arbitration lost. 1 when core lost arbitration
+#define I2C_ST_RSVD_4 (1 << 4) // reserved
+#define I2C_ST_RSVD_3 (1 << 3) // reserved
+#define I2C_ST_RSVD_2 (1 << 2) // reserved
+#define I2C_ST_TIP (1 << 1) // Transfer-in-progress
+#define I2C_ST_IP (1 << 0) // Interrupt pending
+
+using namespace uhd;
+
+class i2c_core_100_impl : public i2c_core_100{
+public:
+ i2c_core_100_impl(wb_iface::sptr iface, const size_t base):
+ _iface(iface), _base(base)
+ {
+ //init I2C FPGA interface.
+ _iface->poke16(REG_I2C_CTRL, 0x0000);
+ //set prescalers to operate at 400kHz: WB_CLK is 64MHz...
+ static const boost::uint32_t i2c_datarate = 400000;
+ static const boost::uint32_t wishbone_clk = 64000000; //FIXME should go somewhere else
+ boost::uint16_t prescaler = wishbone_clk / (i2c_datarate*5) - 1;
+ _iface->poke16(REG_I2C_PRESCALER_LO, prescaler & 0xFF);
+ _iface->poke16(REG_I2C_PRESCALER_HI, (prescaler >> 8) & 0xFF);
+ _iface->poke16(REG_I2C_CTRL, I2C_CTRL_EN); //enable I2C core
+ }
+
+ void write_i2c(
+ boost::uint8_t addr,
+ const byte_vector_t &bytes
+ ){
+ _iface->poke16(REG_I2C_DATA, (addr << 1) | 0); //addr and read bit (0)
+ _iface->poke16(REG_I2C_CMD_STATUS, I2C_CMD_WR | I2C_CMD_START | (bytes.size() == 0 ? I2C_CMD_STOP : 0));
+
+ //wait for previous transfer to complete
+ if (not wait_chk_ack()) {
+ _iface->poke16(REG_I2C_CMD_STATUS, I2C_CMD_STOP);
+ return;
+ }
+
+ for (size_t i = 0; i < bytes.size(); i++) {
+ _iface->poke16(REG_I2C_DATA, bytes[i]);
+ _iface->poke16(REG_I2C_CMD_STATUS, I2C_CMD_WR | ((i == (bytes.size() - 1)) ? I2C_CMD_STOP : 0));
+ if(!wait_chk_ack()) {
+ _iface->poke16(REG_I2C_CMD_STATUS, I2C_CMD_STOP);
+ return;
+ }
+ }
+ }
+
+ byte_vector_t read_i2c(
+ boost::uint8_t addr,
+ size_t num_bytes
+ ){
+ byte_vector_t bytes;
+ if (num_bytes == 0) return bytes;
+
+ while (_iface->peek16(REG_I2C_CMD_STATUS) & I2C_ST_BUSY);
+
+ _iface->poke16(REG_I2C_DATA, (addr << 1) | 1); //addr and read bit (1)
+ _iface->poke16(REG_I2C_CMD_STATUS, I2C_CMD_WR | I2C_CMD_START);
+ //wait for previous transfer to complete
+ if (not wait_chk_ack()) {
+ _iface->poke16(REG_I2C_CMD_STATUS, I2C_CMD_STOP);
+ }
+ for (size_t i = 0; i < num_bytes; i++) {
+ _iface->poke16(REG_I2C_CMD_STATUS, I2C_CMD_RD | ((num_bytes == i+1) ? (I2C_CMD_STOP | I2C_CMD_NACK) : 0));
+ i2c_wait();
+ bytes.push_back(boost::uint8_t(_iface->peek16(REG_I2C_DATA)));
+ }
+ return bytes;
+ }
+
+private:
+ void i2c_wait(void) {
+ for (size_t i = 0; i < 100; i++){
+ if ((_iface->peek16(REG_I2C_CMD_STATUS) & I2C_ST_TIP) == 0) return;
+ boost::this_thread::sleep(boost::posix_time::milliseconds(1));
+ }
+ UHD_MSG(error) << "i2c_core_100: i2c_wait timeout" << std::endl;
+ }
+
+ bool wait_chk_ack(void){
+ i2c_wait();
+ return (_iface->peek16(REG_I2C_CMD_STATUS) & I2C_ST_RXACK) == 0;
+ }
+
+ wb_iface::sptr _iface;
+ const size_t _base;
+};
+
+i2c_core_100::sptr i2c_core_100::make(wb_iface::sptr iface, const size_t base){
+ return sptr(new i2c_core_100_impl(iface, base));
+}
diff --git a/fpga/usrp2/top/E1x0/passthru.v b/host/lib/usrp/cores/i2c_core_100.hpp
index 486257366..f7a5ae4f7 100644
--- a/fpga/usrp2/top/E1x0/passthru.v
+++ b/host/lib/usrp/cores/i2c_core_100.hpp
@@ -15,21 +15,21 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
-`timescale 1ns / 1ps
-//////////////////////////////////////////////////////////////////////////////////
+#ifndef INCLUDED_LIBUHD_USRP_I2C_CORE_100_HPP
+#define INCLUDED_LIBUHD_USRP_I2C_CORE_100_HPP
-module passthru
- (input overo_gpio145,
- output cgen_sclk,
- output cgen_sen_b,
- output cgen_mosi,
- input fpga_cfg_din,
- input fpga_cfg_cclk
- );
-
- assign cgen_sclk = fpga_cfg_cclk;
- assign cgen_sen_b = overo_gpio145;
- assign cgen_mosi = fpga_cfg_din;
-
-
-endmodule // passthru
+#include <uhd/config.hpp>
+#include <uhd/types/serial.hpp>
+#include <boost/utility.hpp>
+#include <boost/shared_ptr.hpp>
+#include "wb_iface.hpp"
+
+class i2c_core_100 : boost::noncopyable, public uhd::i2c_iface{
+public:
+ typedef boost::shared_ptr<i2c_core_100> sptr;
+
+ //! makes a new i2c core from iface and slave base
+ static sptr make(wb_iface::sptr iface, const size_t base);
+};
+
+#endif /* INCLUDED_LIBUHD_USRP_I2C_CORE_100_HPP */
diff --git a/host/lib/usrp/cores/rx_dsp_core_200.cpp b/host/lib/usrp/cores/rx_dsp_core_200.cpp
new file mode 100644
index 000000000..82bc7c1bf
--- /dev/null
+++ b/host/lib/usrp/cores/rx_dsp_core_200.cpp
@@ -0,0 +1,202 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// 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 "rx_dsp_core_200.hpp"
+#include <uhd/types/dict.hpp>
+#include <uhd/exception.hpp>
+#include <uhd/utils/algorithm.hpp>
+#include <boost/assign/list_of.hpp>
+#include <boost/math/special_functions/round.hpp>
+#include <boost/math/special_functions/sign.hpp>
+#include <algorithm>
+#include <cmath>
+
+#define REG_DSP_RX_FREQ _dsp_base + 0
+//skip one right here
+#define REG_DSP_RX_DECIM _dsp_base + 8
+#define REG_DSP_RX_MUX _dsp_base + 12
+
+#define FLAG_DSP_RX_MUX_SWAP_IQ (1 << 0)
+#define FLAG_DSP_RX_MUX_REAL_MODE (1 << 1)
+
+#define REG_RX_CTRL_STREAM_CMD _ctrl_base + 0
+#define REG_RX_CTRL_TIME_SECS _ctrl_base + 4
+#define REG_RX_CTRL_TIME_TICKS _ctrl_base + 8
+#define REG_RX_CTRL_CLEAR _ctrl_base + 12
+#define REG_RX_CTRL_VRT_HDR _ctrl_base + 16
+#define REG_RX_CTRL_VRT_SID _ctrl_base + 20
+#define REG_RX_CTRL_VRT_TLR _ctrl_base + 24
+#define REG_RX_CTRL_NSAMPS_PP _ctrl_base + 28
+#define REG_RX_CTRL_NCHANNELS _ctrl_base + 32
+
+template <class T> T ceil_log2(T num){
+ return std::ceil(std::log(num)/std::log(T(2)));
+}
+
+using namespace uhd;
+
+class rx_dsp_core_200_impl : public rx_dsp_core_200{
+public:
+ rx_dsp_core_200_impl(
+ wb_iface::sptr iface,
+ const size_t dsp_base, const size_t ctrl_base,
+ const boost::uint32_t sid, const bool lingering_packet
+ ):
+ _iface(iface), _dsp_base(dsp_base), _ctrl_base(ctrl_base)
+ {
+ //This is a hack/fix for the lingering packet problem.
+ //The caller should also flush the recv transports
+ if (lingering_packet){
+ stream_cmd_t stream_cmd(stream_cmd_t::STREAM_MODE_NUM_SAMPS_AND_DONE);
+ stream_cmd.num_samps = 1;
+ issue_stream_command(stream_cmd);
+ }
+
+ _iface->poke32(REG_RX_CTRL_CLEAR, 1); //reset
+ _iface->poke32(REG_RX_CTRL_NCHANNELS, 1);
+ _iface->poke32(REG_RX_CTRL_VRT_HDR, 0
+ | (0x1 << 28) //if data with stream id
+ | (0x1 << 26) //has trailer
+ | (0x3 << 22) //integer time other
+ | (0x1 << 20) //fractional time sample count
+ );
+ _iface->poke32(REG_RX_CTRL_VRT_SID, sid);
+ _iface->poke32(REG_RX_CTRL_VRT_TLR, 0);
+ }
+
+ void set_nsamps_per_packet(const size_t nsamps){
+ _iface->poke32(REG_RX_CTRL_NSAMPS_PP, nsamps);
+ }
+
+ void issue_stream_command(const stream_cmd_t &stream_cmd){
+ UHD_ASSERT_THROW(stream_cmd.num_samps <= 0x3fffffff);
+ _continuous_streaming = stream_cmd.stream_mode == stream_cmd_t::STREAM_MODE_START_CONTINUOUS;
+
+ //setup the mode to instruction flags
+ typedef boost::tuple<bool, bool, bool> inst_t;
+ static const uhd::dict<stream_cmd_t::stream_mode_t, inst_t> mode_to_inst = boost::assign::map_list_of
+ //reload, chain, samps
+ (stream_cmd_t::STREAM_MODE_START_CONTINUOUS, inst_t(true, true, false))
+ (stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS, inst_t(false, false, false))
+ (stream_cmd_t::STREAM_MODE_NUM_SAMPS_AND_DONE, inst_t(false, false, true))
+ (stream_cmd_t::STREAM_MODE_NUM_SAMPS_AND_MORE, inst_t(false, true, true))
+ ;
+
+ //setup the instruction flag values
+ bool inst_reload, inst_chain, inst_samps;
+ boost::tie(inst_reload, inst_chain, inst_samps) = mode_to_inst[stream_cmd.stream_mode];
+
+ //calculate the word from flags and length
+ boost::uint32_t cmd_word = 0;
+ cmd_word |= boost::uint32_t((stream_cmd.stream_now)? 1 : 0) << 31;
+ cmd_word |= boost::uint32_t((inst_chain)? 1 : 0) << 30;
+ cmd_word |= boost::uint32_t((inst_reload)? 1 : 0) << 29;
+ cmd_word |= (inst_samps)? stream_cmd.num_samps : ((inst_chain)? 1 : 0);
+
+ //issue the stream command
+ _iface->poke32(REG_RX_CTRL_STREAM_CMD, cmd_word);
+ _iface->poke32(REG_RX_CTRL_TIME_SECS, boost::uint32_t(stream_cmd.time_spec.get_full_secs()));
+ _iface->poke32(REG_RX_CTRL_TIME_TICKS, stream_cmd.time_spec.get_tick_count(_tick_rate)); //latches the command
+ }
+
+ void set_mux(const std::string &mode, const bool fe_swapped){
+ static const uhd::dict<std::string, boost::uint32_t> mode_to_mux = boost::assign::map_list_of
+ ("IQ", 0)
+ ("QI", FLAG_DSP_RX_MUX_SWAP_IQ)
+ ("I", FLAG_DSP_RX_MUX_REAL_MODE)
+ ("Q", FLAG_DSP_RX_MUX_SWAP_IQ | FLAG_DSP_RX_MUX_REAL_MODE)
+ ;
+ _iface->poke32(REG_DSP_RX_MUX, mode_to_mux[mode] ^ (fe_swapped? FLAG_DSP_RX_MUX_SWAP_IQ : 0));
+ }
+
+ void set_tick_rate(const double rate){
+ _tick_rate = rate;
+ }
+
+ void set_link_rate(const double rate){
+ _link_rate = rate/sizeof(boost::uint32_t); //in samps/s
+ }
+
+ double set_host_rate(const double rate){
+ const size_t decim_rate = uhd::clip<size_t>(
+ boost::math::iround(_tick_rate/rate), size_t(std::ceil(_tick_rate/_link_rate)), 512
+ );
+ size_t decim = decim_rate;
+
+ //determine which half-band filters are activated
+ int hb0 = 0, hb1 = 0;
+ if (decim % 2 == 0){
+ hb0 = 1;
+ decim /= 2;
+ }
+ if (decim % 2 == 0){
+ hb1 = 1;
+ decim /= 2;
+ }
+
+ _iface->poke32(REG_DSP_RX_DECIM, (hb1 << 9) | (hb0 << 8) | (decim & 0xff));
+
+ // Calculate CIC decimation (i.e., without halfband decimators)
+ // Calculate closest multiplier constant to reverse gain absent scale multipliers
+ const double rate_pow = std::pow(double(decim & 0xff), 4);
+ _scaling_adjustment = std::pow(2, ceil_log2(rate_pow))/(1.65*rate_pow);
+
+ return _tick_rate/decim_rate;
+ }
+
+ double get_scaling_adjustment(void){
+ return _scaling_adjustment;
+ }
+
+ double set_freq(const double freq_){
+ //correct for outside of rate (wrap around)
+ double freq = std::fmod(freq_, _tick_rate);
+ if (std::abs(freq) > _tick_rate/2.0)
+ freq -= boost::math::sign(freq)*_tick_rate;
+
+ //calculate the freq register word (signed)
+ UHD_ASSERT_THROW(std::abs(freq) <= _tick_rate/2.0);
+ static const double scale_factor = std::pow(2.0, 32);
+ const boost::int32_t freq_word = boost::int32_t(boost::math::round((freq / _tick_rate) * scale_factor));
+
+ //update the actual frequency
+ const double actual_freq = (double(freq_word) / scale_factor) * _tick_rate;
+
+ _iface->poke32(REG_DSP_RX_FREQ, boost::uint32_t(freq_word));
+
+ return actual_freq;
+ }
+
+ uhd::meta_range_t get_freq_range(void){
+ return uhd::meta_range_t(-_tick_rate/2, +_tick_rate/2, _tick_rate/std::pow(2.0, 32));
+ }
+
+ void handle_overflow(void){
+ if (_continuous_streaming) issue_stream_command(stream_cmd_t::STREAM_MODE_START_CONTINUOUS);
+ }
+
+private:
+ wb_iface::sptr _iface;
+ const size_t _dsp_base, _ctrl_base;
+ double _tick_rate, _link_rate;
+ bool _continuous_streaming;
+ double _scaling_adjustment;
+};
+
+rx_dsp_core_200::sptr rx_dsp_core_200::make(wb_iface::sptr iface, const size_t dsp_base, const size_t ctrl_base, const boost::uint32_t sid, const bool lingering_packet){
+ return sptr(new rx_dsp_core_200_impl(iface, dsp_base, ctrl_base, sid, lingering_packet));
+}
diff --git a/host/lib/usrp/cores/rx_dsp_core_200.hpp b/host/lib/usrp/cores/rx_dsp_core_200.hpp
new file mode 100644
index 000000000..391cc8441
--- /dev/null
+++ b/host/lib/usrp/cores/rx_dsp_core_200.hpp
@@ -0,0 +1,61 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// 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_RX_DSP_CORE_200_HPP
+#define INCLUDED_LIBUHD_USRP_RX_DSP_CORE_200_HPP
+
+#include <uhd/config.hpp>
+#include <uhd/types/ranges.hpp>
+#include <boost/utility.hpp>
+#include <boost/shared_ptr.hpp>
+#include <uhd/types/stream_cmd.hpp>
+#include "wb_iface.hpp"
+#include <string>
+
+class rx_dsp_core_200 : boost::noncopyable{
+public:
+ typedef boost::shared_ptr<rx_dsp_core_200> sptr;
+
+ static sptr make(
+ wb_iface::sptr iface,
+ const size_t dsp_base, const size_t ctrl_base,
+ const boost::uint32_t sid, const bool lingering_packet = false
+ );
+
+ virtual void set_nsamps_per_packet(const size_t nsamps) = 0;
+
+ virtual void issue_stream_command(const uhd::stream_cmd_t &stream_cmd) = 0;
+
+ virtual void set_mux(const std::string &mode, const bool fe_swapped = false) = 0;
+
+ virtual void set_tick_rate(const double rate) = 0;
+
+ virtual void set_link_rate(const double rate) = 0;
+
+ virtual double set_host_rate(const double rate) = 0;
+
+ virtual double get_scaling_adjustment(void) = 0;
+
+ virtual uhd::meta_range_t get_freq_range(void) = 0;
+
+ virtual double set_freq(const double freq) = 0;
+
+ virtual void handle_overflow(void) = 0;
+
+};
+
+#endif /* INCLUDED_LIBUHD_USRP_RX_DSP_CORE_200_HPP */
diff --git a/host/lib/usrp/cores/rx_frontend_core_200.cpp b/host/lib/usrp/cores/rx_frontend_core_200.cpp
new file mode 100644
index 000000000..0e8220b49
--- /dev/null
+++ b/host/lib/usrp/cores/rx_frontend_core_200.cpp
@@ -0,0 +1,61 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// 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 "rx_frontend_core_200.hpp"
+#include <boost/math/special_functions/round.hpp>
+
+#define REG_RX_FE_SWAP_IQ _base + 0 //lower bit
+#define REG_RX_FE_MAG_CORRECTION _base + 4 //18 bits
+#define REG_RX_FE_PHASE_CORRECTION _base + 8 //18 bits
+#define REG_RX_FE_OFFSET_I _base + 12 //18 bits
+#define REG_RX_FE_OFFSET_Q _base + 16 //18 bits
+
+static boost::uint32_t fs_to_bits(const double num, const size_t bits){
+ return boost::int32_t(boost::math::round(num * (1 << (bits-1))));
+}
+
+
+class rx_frontend_core_200_impl : public rx_frontend_core_200{
+public:
+ rx_frontend_core_200_impl(wb_iface::sptr iface, const size_t base):
+ _iface(iface), _base(base)
+ {
+ //NOP
+ }
+
+ void set_mux(const bool swap){
+ _iface->poke32(REG_RX_FE_SWAP_IQ, swap? 1 : 0);
+ }
+
+ void set_offset(const std::complex<double> &off){
+ _iface->poke32(REG_RX_FE_OFFSET_I, fs_to_bits(off.real(), 24));
+ _iface->poke32(REG_RX_FE_OFFSET_Q, fs_to_bits(off.imag(), 24));
+ }
+
+ void set_correction(const std::complex<double> &cor){
+ _iface->poke32(REG_RX_FE_MAG_CORRECTION, fs_to_bits(std::abs(cor), 18));
+ _iface->poke32(REG_RX_FE_PHASE_CORRECTION, fs_to_bits(std::atan2(cor.real(), cor.imag()), 18));
+ }
+
+private:
+ wb_iface::sptr _iface;
+ const size_t _base;
+};
+
+rx_frontend_core_200::sptr rx_frontend_core_200::make(wb_iface::sptr iface, const size_t base){
+ return sptr(new rx_frontend_core_200_impl(iface, base));
+}
diff --git a/host/lib/usrp/cores/rx_frontend_core_200.hpp b/host/lib/usrp/cores/rx_frontend_core_200.hpp
new file mode 100644
index 000000000..a950e2bb7
--- /dev/null
+++ b/host/lib/usrp/cores/rx_frontend_core_200.hpp
@@ -0,0 +1,42 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// 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_TX_FRONTEND_CORE_200_HPP
+#define INCLUDED_LIBUHD_USRP_TX_FRONTEND_CORE_200_HPP
+
+#include <uhd/config.hpp>
+#include <boost/utility.hpp>
+#include <boost/shared_ptr.hpp>
+#include "wb_iface.hpp"
+#include <complex>
+#include <string>
+
+class rx_frontend_core_200 : boost::noncopyable{
+public:
+ typedef boost::shared_ptr<rx_frontend_core_200> sptr;
+
+ static sptr make(wb_iface::sptr iface, const size_t base);
+
+ virtual void set_mux(const bool swap) = 0;
+
+ virtual void set_offset(const std::complex<double> &off) = 0;
+
+ virtual void set_correction(const std::complex<double> &cor) = 0;
+
+};
+
+#endif /* INCLUDED_LIBUHD_USRP_TX_FRONTEND_CORE_200_HPP */
diff --git a/host/lib/usrp/cores/spi_core_100.cpp b/host/lib/usrp/cores/spi_core_100.cpp
new file mode 100644
index 000000000..d11a499a9
--- /dev/null
+++ b/host/lib/usrp/cores/spi_core_100.cpp
@@ -0,0 +1,88 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// 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 "spi_core_100.hpp"
+#include <uhd/exception.hpp>
+#include <uhd/utils/msg.hpp>
+#include <boost/thread/thread.hpp> //sleep
+
+#define REG_SPI_TXRX0 _base + 0
+#define REG_SPI_TXRX1 _base + 4
+#define REG_SPI_TXRX2 _base + 8
+#define REG_SPI_TXRX3 _base + 12
+#define REG_SPI_CTRL _base + 16
+#define REG_SPI_DIV _base + 20
+#define REG_SPI_SS _base + 24
+
+//spi ctrl register bit definitions
+#define SPI_CTRL_ASS (1<<13)
+#define SPI_CTRL_IE (1<<12)
+#define SPI_CTRL_LSB (1<<11)
+#define SPI_CTRL_TXNEG (1<<10) //mosi edge, push on falling edge when 1
+#define SPI_CTRL_RXNEG (1<< 9) //miso edge, latch on falling edge when 1
+#define SPI_CTRL_GO_BSY (1<< 8)
+#define SPI_CTRL_CHAR_LEN_MASK 0x7F
+
+using namespace uhd;
+
+class spi_core_100_impl : public spi_core_100{
+public:
+ spi_core_100_impl(wb_iface::sptr iface, const size_t base):
+ _iface(iface), _base(base) { /* NOP */}
+
+ boost::uint32_t transact_spi(
+ int which_slave,
+ const spi_config_t &config,
+ boost::uint32_t data,
+ size_t num_bits,
+ bool readback
+ ){
+ UHD_ASSERT_THROW(num_bits <= 32 and (num_bits % 8) == 0);
+
+ int edge_flags = ((config.miso_edge==spi_config_t::EDGE_FALL) ? SPI_CTRL_RXNEG : 0) |
+ ((config.mosi_edge==spi_config_t::EDGE_FALL) ? 0 : SPI_CTRL_TXNEG)
+ ;
+ boost::uint16_t ctrl = SPI_CTRL_ASS | (SPI_CTRL_CHAR_LEN_MASK & num_bits) | edge_flags;
+
+ spi_wait();
+ _iface->poke16(REG_SPI_DIV, 0x0001); // = fpga_clk / 4
+ _iface->poke32(REG_SPI_SS, which_slave & 0xFFFF);
+ _iface->poke32(REG_SPI_TXRX0, data);
+ _iface->poke16(REG_SPI_CTRL, ctrl);
+ _iface->poke16(REG_SPI_CTRL, ctrl | SPI_CTRL_GO_BSY);
+
+ if (not readback) return 0;
+ spi_wait();
+ return _iface->peek32(REG_SPI_TXRX0);
+ }
+
+private:
+ void spi_wait(void) {
+ for (size_t i = 0; i < 100; i++){
+ if ((_iface->peek16(REG_SPI_CTRL) & SPI_CTRL_GO_BSY) == 0) return;
+ boost::this_thread::sleep(boost::posix_time::milliseconds(1));
+ }
+ UHD_MSG(error) << "spi_core_100: spi_wait timeout" << std::endl;
+ }
+
+ wb_iface::sptr _iface;
+ const size_t _base;
+};
+
+spi_core_100::sptr spi_core_100::make(wb_iface::sptr iface, const size_t base){
+ return sptr(new spi_core_100_impl(iface, base));
+}
diff --git a/host/lib/usrp/cores/spi_core_100.hpp b/host/lib/usrp/cores/spi_core_100.hpp
new file mode 100644
index 000000000..87d328aaa
--- /dev/null
+++ b/host/lib/usrp/cores/spi_core_100.hpp
@@ -0,0 +1,35 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// 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_SPI_CORE_100_HPP
+#define INCLUDED_LIBUHD_USRP_SPI_CORE_100_HPP
+
+#include <uhd/config.hpp>
+#include <uhd/types/serial.hpp>
+#include <boost/utility.hpp>
+#include <boost/shared_ptr.hpp>
+#include "wb_iface.hpp"
+
+class spi_core_100 : boost::noncopyable, public uhd::spi_iface{
+public:
+ typedef boost::shared_ptr<spi_core_100> sptr;
+
+ //! makes a new spi core from iface and slave base
+ static sptr make(wb_iface::sptr iface, const size_t base);
+};
+
+#endif /* INCLUDED_LIBUHD_USRP_SPI_CORE_100_HPP */
diff --git a/host/lib/usrp/cores/time64_core_200.cpp b/host/lib/usrp/cores/time64_core_200.cpp
new file mode 100644
index 000000000..23d1bdea2
--- /dev/null
+++ b/host/lib/usrp/cores/time64_core_200.cpp
@@ -0,0 +1,132 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// 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 "time64_core_200.hpp"
+#include <uhd/exception.hpp>
+#include <uhd/utils/assert_has.hpp>
+#include <boost/math/special_functions/round.hpp>
+
+#define REG_TIME64_SECS _base + 0
+#define REG_TIME64_TICKS _base + 4
+#define REG_TIME64_FLAGS _base + 8
+#define REG_TIME64_IMM _base + 12
+#define REG_TIME64_TPS _base + 16
+#define REG_TIME64_MIMO_SYNC _base + 20 //lower byte is delay cycles
+
+//pps flags (see above)
+#define FLAG_TIME64_PPS_NEGEDGE (0 << 0)
+#define FLAG_TIME64_PPS_POSEDGE (1 << 0)
+#define FLAG_TIME64_PPS_SMA (0 << 1)
+#define FLAG_TIME64_PPS_MIMO (1 << 1) //apparently not used
+
+#define FLAG_TIME64_LATCH_NOW 1
+#define FLAG_TIME64_LATCH_NEXT_PPS 0
+
+#define FLAG_TIME64_MIMO_SYNC (1 << 8)
+
+using namespace uhd;
+
+class time64_core_200_impl : public time64_core_200{
+public:
+ time64_core_200_impl(
+ wb_iface::sptr iface, const size_t base,
+ const readback_bases_type &readback_bases,
+ const size_t mimo_delay_cycles
+ ):
+ _iface(iface), _base(base),
+ _readback_bases(readback_bases),
+ _mimo_delay_cycles(mimo_delay_cycles)
+ {
+ _sources.push_back("none");
+ _sources.push_back("external");
+ _sources.push_back("_external_");
+ if (_mimo_delay_cycles != 0) _sources.push_back("mimo");
+ }
+
+ void set_tick_rate(const double rate){
+ _tick_rate = rate;
+ _iface->poke32(REG_TIME64_TPS, boost::math::iround(rate));
+ }
+
+ uhd::time_spec_t get_time_now(void){
+ for (size_t i = 0; i < 3; i++){ //special algorithm because we cant read 64 bits synchronously
+ const boost::uint32_t secs = _iface->peek32(_readback_bases.rb_secs_now);
+ const boost::uint32_t ticks = _iface->peek32(_readback_bases.rb_ticks_now);
+ if (secs != _iface->peek32(_readback_bases.rb_secs_now)) continue;
+ return time_spec_t(secs, ticks, _tick_rate);
+ }
+ throw uhd::runtime_error("time64_core_200: get time now timeout");
+ }
+
+ uhd::time_spec_t get_time_last_pps(void){
+ for (size_t i = 0; i < 3; i++){ //special algorithm because we cant read 64 bits synchronously
+ const boost::uint32_t secs = _iface->peek32(_readback_bases.rb_secs_pps);
+ const boost::uint32_t ticks = _iface->peek32(_readback_bases.rb_ticks_pps);
+ if (secs != _iface->peek32(_readback_bases.rb_secs_pps)) continue;
+ return time_spec_t(secs, ticks, _tick_rate);
+ }
+ throw uhd::runtime_error("time64_core_200: get time last pps timeout");
+ }
+
+ void set_time_now(const uhd::time_spec_t &time){
+ _iface->poke32(REG_TIME64_TICKS, time.get_tick_count(_tick_rate));
+ _iface->poke32(REG_TIME64_IMM, FLAG_TIME64_LATCH_NOW);
+ _iface->poke32(REG_TIME64_SECS, boost::uint32_t(time.get_full_secs())); //latches all 3
+ }
+
+ void set_time_next_pps(const uhd::time_spec_t &time){
+ _iface->poke32(REG_TIME64_TICKS, time.get_tick_count(_tick_rate));
+ _iface->poke32(REG_TIME64_IMM, FLAG_TIME64_LATCH_NEXT_PPS);
+ _iface->poke32(REG_TIME64_SECS, boost::uint32_t(time.get_full_secs())); //latches all 3
+ }
+
+ void set_time_source(const std::string &source){
+ assert_has(_sources, source, "time source");
+
+ //setup pps flags
+ if (source == "external"){
+ _iface->poke32(REG_TIME64_FLAGS, FLAG_TIME64_PPS_SMA | FLAG_TIME64_PPS_POSEDGE);
+ }
+ else if (source == "_external_"){
+ _iface->poke32(REG_TIME64_FLAGS, FLAG_TIME64_PPS_SMA | FLAG_TIME64_PPS_NEGEDGE);
+ }
+
+ //setup mimo flags
+ if (source == "mimo"){
+ _iface->poke32(REG_TIME64_MIMO_SYNC, FLAG_TIME64_MIMO_SYNC | (_mimo_delay_cycles & 0xff));
+ }
+ else{
+ _iface->poke32(REG_TIME64_MIMO_SYNC, 0);
+ }
+ }
+
+ std::vector<std::string> get_time_sources(void){
+ return _sources;
+ }
+
+private:
+ wb_iface::sptr _iface;
+ const size_t _base;
+ const readback_bases_type _readback_bases;
+ double _tick_rate;
+ const size_t _mimo_delay_cycles;
+ std::vector<std::string> _sources;
+};
+
+time64_core_200::sptr time64_core_200::make(wb_iface::sptr iface, const size_t base, const readback_bases_type &readback_bases, const size_t mimo_delay_cycles){
+ return sptr(new time64_core_200_impl(iface, base, readback_bases, mimo_delay_cycles));
+}
diff --git a/host/lib/usrp/cores/time64_core_200.hpp b/host/lib/usrp/cores/time64_core_200.hpp
new file mode 100644
index 000000000..ebd51a02f
--- /dev/null
+++ b/host/lib/usrp/cores/time64_core_200.hpp
@@ -0,0 +1,61 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// 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_TIME64_CORE_200_HPP
+#define INCLUDED_LIBUHD_USRP_TIME64_CORE_200_HPP
+
+#include <uhd/config.hpp>
+#include <uhd/types/time_spec.hpp>
+#include <boost/utility.hpp>
+#include <boost/shared_ptr.hpp>
+#include "wb_iface.hpp"
+#include <string>
+#include <vector>
+
+class time64_core_200 : boost::noncopyable{
+public:
+ typedef boost::shared_ptr<time64_core_200> sptr;
+
+ struct readback_bases_type{
+ size_t rb_secs_now, rb_ticks_now;
+ size_t rb_secs_pps, rb_ticks_pps;
+ };
+
+ //! makes a new time64 core from iface and slave base
+ static sptr make(
+ wb_iface::sptr iface, const size_t base,
+ const readback_bases_type &readback_bases,
+ const size_t mimo_delay_cycles = 0 // 0 means no-mimo
+ );
+
+ virtual void set_tick_rate(const double rate) = 0;
+
+ virtual uhd::time_spec_t get_time_now(void) = 0;
+
+ virtual uhd::time_spec_t get_time_last_pps(void) = 0;
+
+ virtual void set_time_now(const uhd::time_spec_t &time) = 0;
+
+ virtual void set_time_next_pps(const uhd::time_spec_t &time) = 0;
+
+ virtual void set_time_source(const std::string &source) = 0;
+
+ virtual std::vector<std::string> get_time_sources(void) = 0;
+
+};
+
+#endif /* INCLUDED_LIBUHD_USRP_TIME64_CORE_200_HPP */
diff --git a/host/lib/usrp/cores/tx_dsp_core_200.cpp b/host/lib/usrp/cores/tx_dsp_core_200.cpp
new file mode 100644
index 000000000..222ba589a
--- /dev/null
+++ b/host/lib/usrp/cores/tx_dsp_core_200.cpp
@@ -0,0 +1,140 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// 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 "tx_dsp_core_200.hpp"
+#include <uhd/types/dict.hpp>
+#include <uhd/exception.hpp>
+#include <uhd/utils/algorithm.hpp>
+#include <boost/assign/list_of.hpp>
+#include <boost/math/special_functions/round.hpp>
+#include <boost/math/special_functions/sign.hpp>
+#include <algorithm>
+#include <cmath>
+
+#define REG_DSP_TX_FREQ _dsp_base + 0
+#define REG_DSP_TX_SCALE_IQ _dsp_base + 4
+#define REG_DSP_TX_INTERP _dsp_base + 8
+
+#define REG_TX_CTRL_NUM_CHAN _ctrl_base + 0
+#define REG_TX_CTRL_CLEAR_STATE _ctrl_base + 4
+#define REG_TX_CTRL_REPORT_SID _ctrl_base + 8
+#define REG_TX_CTRL_POLICY _ctrl_base + 12
+#define REG_TX_CTRL_CYCLES_PER_UP _ctrl_base + 16
+#define REG_TX_CTRL_PACKETS_PER_UP _ctrl_base + 20
+
+#define FLAG_TX_CTRL_POLICY_WAIT (0x1 << 0)
+#define FLAG_TX_CTRL_POLICY_NEXT_PACKET (0x1 << 1)
+#define FLAG_TX_CTRL_POLICY_NEXT_BURST (0x1 << 2)
+
+//enable flag for registers: cycles and packets per update packet
+#define FLAG_TX_CTRL_UP_ENB (1ul << 31)
+
+template <class T> T ceil_log2(T num){
+ return std::ceil(std::log(num)/std::log(T(2)));
+}
+
+using namespace uhd;
+
+class tx_dsp_core_200_impl : public tx_dsp_core_200{
+public:
+ tx_dsp_core_200_impl(
+ wb_iface::sptr iface,
+ const size_t dsp_base, const size_t ctrl_base,
+ const boost::uint32_t sid
+ ):
+ _iface(iface), _dsp_base(dsp_base), _ctrl_base(ctrl_base)
+ {
+ //init the tx control registers
+ _iface->poke32(REG_TX_CTRL_CLEAR_STATE, 1); //reset
+ _iface->poke32(REG_TX_CTRL_NUM_CHAN, 0); //1 channel
+ _iface->poke32(REG_TX_CTRL_REPORT_SID, sid);
+ _iface->poke32(REG_TX_CTRL_POLICY, FLAG_TX_CTRL_POLICY_NEXT_PACKET);
+ }
+
+ void set_tick_rate(const double rate){
+ _tick_rate = rate;
+ }
+
+ void set_link_rate(const double rate){
+ _link_rate = rate/sizeof(boost::uint32_t); //in samps/s
+ }
+
+ double set_host_rate(const double rate){
+ const size_t interp_rate = uhd::clip<size_t>(
+ boost::math::iround(_tick_rate/rate), size_t(std::ceil(_tick_rate/_link_rate)), 512
+ );
+ size_t interp = interp_rate;
+
+ //determine which half-band filters are activated
+ int hb0 = 0, hb1 = 0;
+ if (interp % 2 == 0){
+ hb0 = 1;
+ interp /= 2;
+ }
+ if (interp % 2 == 0){
+ hb1 = 1;
+ interp /= 2;
+ }
+
+ _iface->poke32(REG_DSP_TX_INTERP, (hb1 << 9) | (hb0 << 8) | (interp & 0xff));
+
+ // Calculate CIC interpolation (i.e., without halfband interpolators)
+ // Calculate closest multiplier constant to reverse gain absent scale multipliers
+ double rate_cubed = std::pow(double(interp & 0xff), 3);
+ const boost::int16_t scale = boost::math::iround((4096*std::pow(2, ceil_log2(rate_cubed)))/(1.65*rate_cubed));
+ _iface->poke32(REG_DSP_TX_SCALE_IQ, (boost::uint32_t(scale) << 16) | (boost::uint32_t(scale) << 0));
+
+ return _tick_rate/interp_rate;
+ }
+
+ double set_freq(const double freq_){
+ //correct for outside of rate (wrap around)
+ double freq = std::fmod(freq_, _tick_rate);
+ if (std::abs(freq) > _tick_rate/2.0)
+ freq -= boost::math::sign(freq)*_tick_rate;
+
+ //calculate the freq register word (signed)
+ UHD_ASSERT_THROW(std::abs(freq) <= _tick_rate/2.0);
+ static const double scale_factor = std::pow(2.0, 32);
+ const boost::int32_t freq_word = boost::int32_t(boost::math::round((freq / _tick_rate) * scale_factor));
+
+ //update the actual frequency
+ const double actual_freq = (double(freq_word) / scale_factor) * _tick_rate;
+
+ _iface->poke32(REG_DSP_TX_FREQ, boost::uint32_t(freq_word));
+
+ return actual_freq;
+ }
+
+ uhd::meta_range_t get_freq_range(void){
+ return uhd::meta_range_t(-_tick_rate/2, +_tick_rate/2, _tick_rate/std::pow(2.0, 32));
+ }
+
+ void set_updates(const size_t cycles_per_up, const size_t packets_per_up){
+ _iface->poke32(REG_TX_CTRL_CYCLES_PER_UP, (cycles_per_up == 0)? 0 : (FLAG_TX_CTRL_UP_ENB | cycles_per_up));
+ _iface->poke32(REG_TX_CTRL_PACKETS_PER_UP, (packets_per_up == 0)? 0 : (FLAG_TX_CTRL_UP_ENB | packets_per_up));
+ }
+
+private:
+ wb_iface::sptr _iface;
+ const size_t _dsp_base, _ctrl_base;
+ double _tick_rate, _link_rate;
+};
+
+tx_dsp_core_200::sptr tx_dsp_core_200::make(wb_iface::sptr iface, const size_t dsp_base, const size_t ctrl_base, const boost::uint32_t sid){
+ return sptr(new tx_dsp_core_200_impl(iface, dsp_base, ctrl_base, sid));
+}
diff --git a/host/lib/usrp/cores/tx_dsp_core_200.hpp b/host/lib/usrp/cores/tx_dsp_core_200.hpp
new file mode 100644
index 000000000..65f822558
--- /dev/null
+++ b/host/lib/usrp/cores/tx_dsp_core_200.hpp
@@ -0,0 +1,51 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// 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_TX_DSP_CORE_200_HPP
+#define INCLUDED_LIBUHD_USRP_TX_DSP_CORE_200_HPP
+
+#include <uhd/config.hpp>
+#include <uhd/types/ranges.hpp>
+#include <boost/utility.hpp>
+#include <boost/shared_ptr.hpp>
+#include "wb_iface.hpp"
+
+class tx_dsp_core_200 : boost::noncopyable{
+public:
+ typedef boost::shared_ptr<tx_dsp_core_200> sptr;
+
+ static sptr make(
+ wb_iface::sptr iface,
+ const size_t dsp_base, const size_t ctrl_base,
+ const boost::uint32_t sid
+ );
+
+ virtual void set_tick_rate(const double rate) = 0;
+
+ virtual void set_link_rate(const double rate) = 0;
+
+ virtual double set_host_rate(const double rate) = 0;
+
+ virtual uhd::meta_range_t get_freq_range(void) = 0;
+
+ virtual double set_freq(const double freq) = 0;
+
+ virtual void set_updates(const size_t cycles_per_up, const size_t packets_per_up) = 0;
+
+};
+
+#endif /* INCLUDED_LIBUHD_USRP_TX_DSP_CORE_200_HPP */
diff --git a/host/lib/usrp/cores/tx_frontend_core_200.cpp b/host/lib/usrp/cores/tx_frontend_core_200.cpp
new file mode 100644
index 000000000..a7568a81e
--- /dev/null
+++ b/host/lib/usrp/cores/tx_frontend_core_200.cpp
@@ -0,0 +1,70 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// 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 "tx_frontend_core_200.hpp"
+#include <uhd/types/dict.hpp>
+#include <uhd/exception.hpp>
+#include <boost/assign/list_of.hpp>
+#include <boost/math/special_functions/round.hpp>
+
+#define REG_TX_FE_DC_OFFSET_I _base + 0 //24 bits
+#define REG_TX_FE_DC_OFFSET_Q _base + 4 //24 bits
+#define REG_TX_FE_MAG_CORRECTION _base + 8 //18 bits
+#define REG_TX_FE_PHASE_CORRECTION _base + 12 //18 bits
+#define REG_TX_FE_MUX _base + 16 //8 bits (std output = 0x10, reversed = 0x01)
+
+static boost::uint32_t fs_to_bits(const double num, const size_t bits){
+ return boost::int32_t(boost::math::round(num * (1 << (bits-1))));
+}
+
+
+class tx_frontend_core_200_impl : public tx_frontend_core_200{
+public:
+ tx_frontend_core_200_impl(wb_iface::sptr iface, const size_t base):
+ _iface(iface), _base(base)
+ {
+ //NOP
+ }
+
+ void set_mux(const std::string &mode){
+ static const uhd::dict<std::string, boost::uint32_t> mode_to_mux = boost::assign::map_list_of
+ ("IQ", (0x1 << 4) | (0x0 << 0)) //DAC0Q=DUC0Q, DAC0I=DUC0I
+ ("QI", (0x0 << 4) | (0x1 << 0)) //DAC0Q=DUC0I, DAC0I=DUC0Q
+ ("I", (0xf << 4) | (0x0 << 0)) //DAC0Q=ZERO, DAC0I=DUC0I
+ ("Q", (0x0 << 4) | (0xf << 0)) //DAC0Q=DUC0I, DAC0I=ZERO
+ ;
+ _iface->poke32(REG_TX_FE_MUX, mode_to_mux[mode]);
+ }
+
+ void set_dc_offset(const std::complex<double> &off){
+ _iface->poke32(REG_TX_FE_DC_OFFSET_I, fs_to_bits(off.real(), 24));
+ _iface->poke32(REG_TX_FE_DC_OFFSET_Q, fs_to_bits(off.imag(), 24));
+ }
+
+ void set_correction(const std::complex<double> &cor){
+ _iface->poke32(REG_TX_FE_MAG_CORRECTION, fs_to_bits(std::abs(cor), 18));
+ _iface->poke32(REG_TX_FE_PHASE_CORRECTION, fs_to_bits(std::atan2(cor.real(), cor.imag()), 18));
+ }
+
+private:
+ wb_iface::sptr _iface;
+ const size_t _base;
+};
+
+tx_frontend_core_200::sptr tx_frontend_core_200::make(wb_iface::sptr iface, const size_t base){
+ return sptr(new tx_frontend_core_200_impl(iface, base));
+}
diff --git a/host/lib/usrp/cores/tx_frontend_core_200.hpp b/host/lib/usrp/cores/tx_frontend_core_200.hpp
new file mode 100644
index 000000000..9e4a7bc79
--- /dev/null
+++ b/host/lib/usrp/cores/tx_frontend_core_200.hpp
@@ -0,0 +1,42 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// 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_RX_FRONTEND_CORE_200_HPP
+#define INCLUDED_LIBUHD_USRP_RX_FRONTEND_CORE_200_HPP
+
+#include <uhd/config.hpp>
+#include <boost/utility.hpp>
+#include <boost/shared_ptr.hpp>
+#include "wb_iface.hpp"
+#include <complex>
+#include <string>
+
+class tx_frontend_core_200 : boost::noncopyable{
+public:
+ typedef boost::shared_ptr<tx_frontend_core_200> sptr;
+
+ static sptr make(wb_iface::sptr iface, const size_t base);
+
+ virtual void set_mux(const std::string &mode) = 0;
+
+ virtual void set_dc_offset(const std::complex<double> &off) = 0;
+
+ virtual void set_correction(const std::complex<double> &cor) = 0;
+
+};
+
+#endif /* INCLUDED_LIBUHD_USRP_RX_FRONTEND_CORE_200_HPP */
diff --git a/host/lib/usrp/cores/wb_iface.hpp b/host/lib/usrp/cores/wb_iface.hpp
new file mode 100644
index 000000000..982594b21
--- /dev/null
+++ b/host/lib/usrp/cores/wb_iface.hpp
@@ -0,0 +1,60 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// 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_WB_IFACE_HPP
+#define INCLUDED_LIBUHD_USRP_WB_IFACE_HPP
+
+#include <uhd/config.hpp>
+#include <boost/cstdint.hpp>
+#include <boost/shared_ptr.hpp>
+
+class wb_iface{
+public:
+ typedef boost::shared_ptr<wb_iface> sptr;
+ typedef boost::uint32_t wb_addr_type;
+
+ /*!
+ * Write a register (32 bits)
+ * \param addr the address
+ * \param data the 32bit data
+ */
+ virtual void poke32(wb_addr_type addr, boost::uint32_t data) = 0;
+
+ /*!
+ * Read a register (32 bits)
+ * \param addr the address
+ * \return the 32bit data
+ */
+ virtual boost::uint32_t peek32(wb_addr_type addr) = 0;
+
+ /*!
+ * Write a register (16 bits)
+ * \param addr the address
+ * \param data the 16bit data
+ */
+ virtual void poke16(wb_addr_type addr, boost::uint16_t data) = 0;
+
+ /*!
+ * Read a register (16 bits)
+ * \param addr the address
+ * \return the 16bit data
+ */
+ virtual boost::uint16_t peek16(wb_addr_type addr) = 0;
+
+};
+
+#endif /* INCLUDED_LIBUHD_USRP_WB_IFACE_HPP */
diff --git a/host/lib/usrp/dboard/db_basic_and_lf.cpp b/host/lib/usrp/dboard/db_basic_and_lf.cpp
index 566e24d97..ff93f1d89 100644
--- a/host/lib/usrp/dboard/db_basic_and_lf.cpp
+++ b/host/lib/usrp/dboard/db_basic_and_lf.cpp
@@ -15,7 +15,6 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
-#include <uhd/usrp/subdev_props.hpp>
#include <uhd/types/dict.hpp>
#include <uhd/types/ranges.hpp>
#include <uhd/utils/assert_has.hpp>
@@ -162,6 +161,10 @@ 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_SENSOR_NAMES:
+ val = prop_names_t(1, ""); //vector of 1 empty string
+ return;
+
case SUBDEV_PROP_CONNECTION:
val = sd_name_to_conn[get_subdev_name()];
return;
@@ -268,6 +271,10 @@ 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_SENSOR_NAMES:
+ val = prop_names_t(1, ""); //vector of 1 empty string
+ return;
+
case SUBDEV_PROP_CONNECTION:
val = sd_name_to_conn[get_subdev_name()];
return;
diff --git a/host/lib/usrp/dboard/db_dbsrx.cpp b/host/lib/usrp/dboard/db_dbsrx.cpp
index cfe06db29..c65c52590 100644
--- a/host/lib/usrp/dboard/db_dbsrx.cpp
+++ b/host/lib/usrp/dboard/db_dbsrx.cpp
@@ -28,7 +28,6 @@
#include <uhd/types/ranges.hpp>
#include <uhd/types/sensors.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>
diff --git a/host/lib/usrp/dboard/db_dbsrx2.cpp b/host/lib/usrp/dboard/db_dbsrx2.cpp
index f646a238f..f19236907 100644
--- a/host/lib/usrp/dboard/db_dbsrx2.cpp
+++ b/host/lib/usrp/dboard/db_dbsrx2.cpp
@@ -25,7 +25,6 @@
#include <uhd/types/ranges.hpp>
#include <uhd/types/sensors.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>
diff --git a/host/lib/usrp/dboard/db_rfx.cpp b/host/lib/usrp/dboard/db_rfx.cpp
index 61f9130d4..14129ef72 100644
--- a/host/lib/usrp/dboard/db_rfx.cpp
+++ b/host/lib/usrp/dboard/db_rfx.cpp
@@ -34,7 +34,6 @@
#include "adf4360_regs.hpp"
#include <uhd/types/dict.hpp>
-#include <uhd/usrp/subdev_props.hpp>
#include <uhd/types/ranges.hpp>
#include <uhd/types/sensors.hpp>
#include <uhd/utils/assert_has.hpp>
diff --git a/host/lib/usrp/dboard/db_sbx.cpp b/host/lib/usrp/dboard/db_sbx.cpp
index 6ca89b81a..aa9556e77 100644
--- a/host/lib/usrp/dboard/db_sbx.cpp
+++ b/host/lib/usrp/dboard/db_sbx.cpp
@@ -74,7 +74,6 @@
#include "adf4350_regs.hpp"
#include <uhd/types/dict.hpp>
-#include <uhd/usrp/subdev_props.hpp>
#include <uhd/types/ranges.hpp>
#include <uhd/types/sensors.hpp>
#include <uhd/utils/assert_has.hpp>
diff --git a/host/lib/usrp/dboard/db_tvrx.cpp b/host/lib/usrp/dboard/db_tvrx.cpp
index 1ff0fb785..3b8b276e0 100644
--- a/host/lib/usrp/dboard/db_tvrx.cpp
+++ b/host/lib/usrp/dboard/db_tvrx.cpp
@@ -35,7 +35,6 @@
#include <uhd/types/ranges.hpp>
#include <uhd/types/sensors.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>
diff --git a/host/lib/usrp/dboard/db_tvrx2.cpp b/host/lib/usrp/dboard/db_tvrx2.cpp
index 39ff90d79..23f203b8c 100644
--- a/host/lib/usrp/dboard/db_tvrx2.cpp
+++ b/host/lib/usrp/dboard/db_tvrx2.cpp
@@ -59,7 +59,6 @@
#include <uhd/types/ranges.hpp>
#include <uhd/types/sensors.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>
diff --git a/host/lib/usrp/dboard/db_unknown.cpp b/host/lib/usrp/dboard/db_unknown.cpp
index 6cacab231..0587d015c 100644
--- a/host/lib/usrp/dboard/db_unknown.cpp
+++ b/host/lib/usrp/dboard/db_unknown.cpp
@@ -15,7 +15,6 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
-#include <uhd/usrp/subdev_props.hpp>
#include <uhd/types/ranges.hpp>
#include <uhd/utils/assert_has.hpp>
#include <uhd/utils/static.hpp>
@@ -142,6 +141,10 @@ 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_SENSOR_NAMES:
+ val = prop_names_t(1, ""); //vector of 1 empty string
+ return;
+
case SUBDEV_PROP_CONNECTION:
val = SUBDEV_CONN_COMPLEX_IQ;
return;
@@ -238,6 +241,10 @@ 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_SENSOR_NAMES:
+ val = prop_names_t(1, ""); //vector of 1 empty string
+ return;
+
case SUBDEV_PROP_CONNECTION:
val = SUBDEV_CONN_COMPLEX_IQ;
return;
diff --git a/host/lib/usrp/dboard/db_wbx_common.cpp b/host/lib/usrp/dboard/db_wbx_common.cpp
index c21ba80dc..1089dc7c2 100644
--- a/host/lib/usrp/dboard/db_wbx_common.cpp
+++ b/host/lib/usrp/dboard/db_wbx_common.cpp
@@ -61,7 +61,6 @@
#include "adf4350_regs.hpp"
#include <uhd/utils/log.hpp>
#include <uhd/types/dict.hpp>
-#include <uhd/usrp/subdev_props.hpp>
#include <uhd/types/ranges.hpp>
#include <uhd/types/sensors.hpp>
#include <uhd/utils/assert_has.hpp>
diff --git a/host/lib/usrp/dboard/db_wbx_simple.cpp b/host/lib/usrp/dboard/db_wbx_simple.cpp
index aa4937b19..990bacbc8 100644
--- a/host/lib/usrp/dboard/db_wbx_simple.cpp
+++ b/host/lib/usrp/dboard/db_wbx_simple.cpp
@@ -26,7 +26,6 @@
#include <uhd/utils/static.hpp>
#include <uhd/utils/assert_has.hpp>
#include <uhd/usrp/dboard_manager.hpp>
-#include <uhd/usrp/subdev_props.hpp>
#include <boost/assign/list_of.hpp>
using namespace uhd;
diff --git a/host/lib/usrp/dboard/db_xcvr2450.cpp b/host/lib/usrp/dboard/db_xcvr2450.cpp
index fcd05ea04..b88eb2a95 100644
--- a/host/lib/usrp/dboard/db_xcvr2450.cpp
+++ b/host/lib/usrp/dboard/db_xcvr2450.cpp
@@ -56,7 +56,6 @@
#include <uhd/types/ranges.hpp>
#include <uhd/types/sensors.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>
diff --git a/host/lib/usrp/dboard_eeprom.cpp b/host/lib/usrp/dboard_eeprom.cpp
index 0dc3471f7..b3cb54c1c 100644
--- a/host/lib/usrp/dboard_eeprom.cpp
+++ b/host/lib/usrp/dboard_eeprom.cpp
@@ -133,7 +133,7 @@ void dboard_eeprom_t::load(i2c_iface &iface, boost::uint8_t addr){
}
}
-void dboard_eeprom_t::store(i2c_iface &iface, boost::uint8_t addr){
+void dboard_eeprom_t::store(i2c_iface &iface, boost::uint8_t addr) const{
byte_vector_t bytes(DB_EEPROM_CLEN, 0); //defaults to all zeros
bytes[DB_EEPROM_MAGIC] = DB_EEPROM_MAGIC_VALUE;
diff --git a/host/lib/usrp/dboard_manager.cpp b/host/lib/usrp/dboard_manager.cpp
index 3cc2ca3c0..3f4b5a511 100644
--- a/host/lib/usrp/dboard_manager.cpp
+++ b/host/lib/usrp/dboard_manager.cpp
@@ -17,7 +17,6 @@
#include "dboard_ctor_args.hpp"
#include <uhd/usrp/dboard_manager.hpp>
-#include <uhd/usrp/subdev_props.hpp>
#include <uhd/utils/msg.hpp>
#include <uhd/utils/log.hpp>
#include <uhd/utils/safe_call.hpp>
@@ -404,3 +403,125 @@ void dboard_manager_impl::set_nice_dboard_if(void){
this->get_tx_subdev(sd_name)[SUBDEV_PROP_ENABLED] = false;
}
}
+
+/***********************************************************************
+ * Populate a properties tree from a subdev waxy object
+ **********************************************************************/
+#include <uhd/types/ranges.hpp>
+#include <uhd/types/sensors.hpp>
+
+static sensor_value_t get_sensor(wax::obj subdev, const std::string &name){
+ return subdev[named_prop_t(SUBDEV_PROP_SENSOR, name)].as<sensor_value_t>();
+}
+
+static void set_gain(wax::obj subdev, const std::string &name, const double gain){
+ subdev[named_prop_t(SUBDEV_PROP_GAIN, name)] = gain;
+}
+
+static double get_gain(wax::obj subdev, const std::string &name){
+ return subdev[named_prop_t(SUBDEV_PROP_GAIN, name)].as<double>();
+}
+
+static meta_range_t get_gain_range(wax::obj subdev, const std::string &name){
+ return subdev[named_prop_t(SUBDEV_PROP_GAIN_RANGE, name)].as<meta_range_t>();
+}
+
+static void set_freq(wax::obj subdev, const double freq){
+ subdev[SUBDEV_PROP_FREQ] = freq;
+}
+
+static double get_freq(wax::obj subdev){
+ return subdev[SUBDEV_PROP_FREQ].as<double>();
+}
+
+static meta_range_t get_freq_range(wax::obj subdev){
+ return subdev[SUBDEV_PROP_FREQ_RANGE].as<meta_range_t>();
+}
+
+static void set_ant(wax::obj subdev, const std::string &ant){
+ subdev[SUBDEV_PROP_ANTENNA] = ant;
+}
+
+static std::string get_ant(wax::obj subdev){
+ return subdev[SUBDEV_PROP_ANTENNA].as<std::string>();
+}
+
+static std::vector<std::string> get_ants(wax::obj subdev){
+ return subdev[SUBDEV_PROP_ANTENNA_NAMES].as<std::vector<std::string> >();
+}
+
+static std::string get_conn(wax::obj subdev){
+ switch(subdev[SUBDEV_PROP_CONNECTION].as<subdev_conn_t>()){
+ case SUBDEV_CONN_COMPLEX_IQ: return "IQ";
+ case SUBDEV_CONN_COMPLEX_QI: return "QI";
+ case SUBDEV_CONN_REAL_I: return "I";
+ case SUBDEV_CONN_REAL_Q: return "Q";
+ }
+ UHD_THROW_INVALID_CODE_PATH();
+}
+
+static bool get_use_lo_off(wax::obj subdev){
+ return subdev[SUBDEV_PROP_USE_LO_OFFSET].as<bool>();
+}
+
+static bool get_set_enb(wax::obj subdev, const bool enb){
+ subdev[SUBDEV_PROP_ENABLED] = enb;
+ return subdev[SUBDEV_PROP_ENABLED].as<bool>();
+}
+
+static void set_bw(wax::obj subdev, const double freq){
+ subdev[SUBDEV_PROP_BANDWIDTH] = freq;
+}
+
+static double get_bw(wax::obj subdev){
+ return subdev[SUBDEV_PROP_BANDWIDTH].as<double>();
+}
+
+void dboard_manager::populate_prop_tree_from_subdev(
+ property_tree::sptr subtree, wax::obj subdev
+){
+ subtree->create<std::string>("name").set(subdev[SUBDEV_PROP_NAME].as<std::string>());
+
+ const prop_names_t sensor_names = subdev[SUBDEV_PROP_SENSOR_NAMES].as<prop_names_t>();
+ BOOST_FOREACH(const std::string &name, sensor_names){
+ subtree->create<sensor_value_t>("sensors/" + name)
+ .publish(boost::bind(&get_sensor, subdev, name));
+ }
+
+ const prop_names_t gain_names = subdev[SUBDEV_PROP_GAIN_NAMES].as<prop_names_t>();
+ subtree->create<int>("gains"); //phony property so this dir exists
+ BOOST_FOREACH(const std::string &name, gain_names){
+ subtree->create<double>("gains/" + name + "/value")
+ .publish(boost::bind(&get_gain, subdev, name))
+ .subscribe(boost::bind(&set_gain, subdev, name, _1));
+ subtree->create<meta_range_t>("gains/" + name + "/range")
+ .publish(boost::bind(&get_gain_range, subdev, name));
+ }
+
+ subtree->create<double>("freq/value")
+ .publish(boost::bind(&get_freq, subdev))
+ .subscribe(boost::bind(&set_freq, subdev, _1));
+
+ subtree->create<meta_range_t>("freq/range")
+ .publish(boost::bind(&get_freq_range, subdev));
+
+ subtree->create<std::string>("antenna/value")
+ .publish(boost::bind(&get_ant, subdev))
+ .subscribe(boost::bind(&set_ant, subdev, _1));
+
+ subtree->create<std::vector<std::string> >("antenna/options")
+ .publish(boost::bind(&get_ants, subdev));
+
+ subtree->create<std::string>("connection")
+ .publish(boost::bind(&get_conn, subdev));
+
+ subtree->create<bool>("enabled")
+ .coerce(boost::bind(&get_set_enb, subdev, _1));
+
+ subtree->create<bool>("use_lo_offset")
+ .publish(boost::bind(&get_use_lo_off, subdev));
+
+ subtree->create<double>("bandwidth/value")
+ .publish(boost::bind(&get_bw, subdev))
+ .subscribe(boost::bind(&set_bw, subdev, _1));
+}
diff --git a/host/lib/usrp/dsp_utils.cpp b/host/lib/usrp/dsp_utils.cpp
deleted file mode 100644
index 2686e895b..000000000
--- a/host/lib/usrp/dsp_utils.cpp
+++ /dev/null
@@ -1,141 +0,0 @@
-//
-// Copyright 2010-2011 Ettus Research LLC
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// 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/dsp_utils.hpp>
-#include <uhd/types/dict.hpp>
-#include <uhd/exception.hpp>
-#include <boost/assign/list_of.hpp>
-#include <boost/tuple/tuple.hpp>
-#include <boost/math/special_functions/round.hpp>
-#include <boost/math/special_functions/sign.hpp>
-#include <algorithm>
-#include <cmath>
-
-using namespace uhd;
-using namespace uhd::usrp;
-
-template <class T> T ceil_log2(T num){
- return std::ceil(std::log(num)/std::log(T(2)));
-}
-
-/*!
- * 3 2 1 0
- * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
- * +-------------------------------+-------+-------+-------+-------+
- * | | DDC0Q | DDC0I |
- * +-------------------------------+-------+-------+-------+-------+
- */
-boost::uint32_t dsp_type1::calc_rx_mux_word(subdev_conn_t subdev_conn){
- switch(subdev_conn){
- case SUBDEV_CONN_COMPLEX_IQ: return (0x1 << 4) | (0x0 << 0); //DDC0Q=ADC0Q, DDC0I=ADC0I
- case SUBDEV_CONN_COMPLEX_QI: return (0x0 << 4) | (0x1 << 0); //DDC0Q=ADC0I, DDC0I=ADC0Q
- case SUBDEV_CONN_REAL_I: return (0xf << 4) | (0x0 << 0); //DDC0Q=ZERO, DDC0I=ADC0I
- case SUBDEV_CONN_REAL_Q: return (0xf << 4) | (0x1 << 0); //DDC0Q=ZERO, DDC0I=ADC0Q
- default: UHD_THROW_INVALID_CODE_PATH();
- }
-}
-
-/*!
- * 3 2 1 0
- * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
- * +-------------------------------+-------+-------+-------+-------+
- * | | DAC0Q | DAC0I |
- * +-------------------------------+-------+-------+-------+-------+
- */
-boost::uint32_t dsp_type1::calc_tx_mux_word(subdev_conn_t subdev_conn){
- switch(subdev_conn){
- case SUBDEV_CONN_COMPLEX_IQ: return (0x1 << 4) | (0x0 << 0); //DAC0Q=DUC0Q, DAC0I=DUC0I
- case SUBDEV_CONN_COMPLEX_QI: return (0x0 << 4) | (0x1 << 0); //DAC0Q=DUC0I, DAC0I=DUC0Q
- case SUBDEV_CONN_REAL_I: return (0xf << 4) | (0x0 << 0); //DAC0Q=ZERO, DAC0I=DUC0I
- case SUBDEV_CONN_REAL_Q: return (0x0 << 4) | (0xf << 0); //DAC0Q=DUC0I, DAC0I=ZERO
- default: UHD_THROW_INVALID_CODE_PATH();
- }
-}
-
-boost::uint32_t dsp_type1::calc_cordic_word_and_update(
- double &freq, double codec_rate
-){
- //correct for outside of rate (wrap around)
- freq = std::fmod(freq, codec_rate);
- if (std::abs(freq) > codec_rate/2.0)
- freq -= boost::math::sign(freq)*codec_rate;
-
- //calculate the freq register word (signed)
- UHD_ASSERT_THROW(std::abs(freq) <= codec_rate/2.0);
- static const double scale_factor = std::pow(2.0, 32);
- 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;
-
- return boost::uint32_t(freq_word);
-}
-
-boost::uint32_t dsp_type1::calc_cic_filter_word(unsigned rate){
- int hb0 = 0, hb1 = 0;
- if (not (rate & 0x1)){
- hb0 = 1;
- rate /= 2;
- }
- if (not (rate & 0x1)){
- hb1 = 1;
- rate /= 2;
- }
- return (hb1 << 9) | (hb0 << 8) | (rate & 0xff);
-}
-
-boost::uint32_t dsp_type1::calc_iq_scale_word(
- boost::int16_t i, boost::int16_t q
-){
- return (boost::uint32_t(i) << 16) | (boost::uint32_t(q) << 0);
-}
-
-boost::uint32_t dsp_type1::calc_iq_scale_word(unsigned rate){
- // Calculate CIC interpolation (i.e., without halfband interpolators)
- unsigned tmp_rate = calc_cic_filter_word(rate) & 0xff;
-
- // Calculate closest multiplier constant to reverse gain absent scale multipliers
- double rate_cubed = std::pow(double(tmp_rate), 3);
- boost::int16_t scale = boost::math::iround((4096*std::pow(2, ceil_log2(rate_cubed)))/(1.65*rate_cubed));
- return calc_iq_scale_word(scale, scale);
-}
-
-boost::uint32_t dsp_type1::calc_stream_cmd_word(const stream_cmd_t &stream_cmd){
- UHD_ASSERT_THROW(stream_cmd.num_samps <= 0x3fffffff);
-
- //setup the mode to instruction flags
- typedef boost::tuple<bool, bool, bool> inst_t;
- static const uhd::dict<stream_cmd_t::stream_mode_t, inst_t> mode_to_inst = boost::assign::map_list_of
- //reload, chain, samps
- (stream_cmd_t::STREAM_MODE_START_CONTINUOUS, inst_t(true, true, false))
- (stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS, inst_t(false, false, false))
- (stream_cmd_t::STREAM_MODE_NUM_SAMPS_AND_DONE, inst_t(false, false, true))
- (stream_cmd_t::STREAM_MODE_NUM_SAMPS_AND_MORE, inst_t(false, true, true))
- ;
-
- //setup the instruction flag values
- bool inst_reload, inst_chain, inst_samps;
- boost::tie(inst_reload, inst_chain, inst_samps) = mode_to_inst[stream_cmd.stream_mode];
-
- //calculate the word from flags and length
- boost::uint32_t word = 0;
- word |= boost::uint32_t((stream_cmd.stream_now)? 1 : 0) << 31;
- word |= boost::uint32_t((inst_chain)? 1 : 0) << 30;
- word |= boost::uint32_t((inst_reload)? 1 : 0) << 29;
- word |= (inst_samps)? stream_cmd.num_samps : ((inst_chain)? 1 : 0);
- return word;
-}
diff --git a/host/lib/usrp/usrp_e100/CMakeLists.txt b/host/lib/usrp/e100/CMakeLists.txt
index d0e20a3d8..ac9d8c655 100644
--- a/host/lib/usrp/usrp_e100/CMakeLists.txt
+++ b/host/lib/usrp/e100/CMakeLists.txt
@@ -22,28 +22,19 @@
########################################################################
# Conditionally configure the USRP-E100 support
########################################################################
-LIBUHD_REGISTER_COMPONENT("USRP-E100" ENABLE_USRP_E100 OFF "ENABLE_LIBUHD;LINUX" OFF)
+LIBUHD_REGISTER_COMPONENT("E100" ENABLE_E100 OFF "ENABLE_LIBUHD;LINUX" OFF)
-IF(ENABLE_USRP_E100)
+IF(ENABLE_E100)
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/include)
LIBUHD_APPEND_SOURCES(
${CMAKE_CURRENT_SOURCE_DIR}/clock_ctrl.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/clock_ctrl.hpp
${CMAKE_CURRENT_SOURCE_DIR}/codec_ctrl.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/codec_ctrl.hpp
- ${CMAKE_CURRENT_SOURCE_DIR}/codec_impl.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/dboard_impl.cpp
${CMAKE_CURRENT_SOURCE_DIR}/dboard_iface.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/dsp_impl.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/e100_ctrl.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/e100_impl.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/e100_mmap_zero_copy.cpp
${CMAKE_CURRENT_SOURCE_DIR}/fpga_downloader.cpp
${CMAKE_CURRENT_SOURCE_DIR}/io_impl.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/mboard_impl.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/usrp_e100_impl.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/usrp_e100_impl.hpp
- ${CMAKE_CURRENT_SOURCE_DIR}/usrp_e100_iface.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/usrp_e100_iface.hpp
- ${CMAKE_CURRENT_SOURCE_DIR}/usrp_e100_mmap_zero_copy.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/usrp_e100_regs.hpp
)
-ENDIF(ENABLE_USRP_E100)
+ENDIF(ENABLE_E100)
diff --git a/host/lib/usrp/usrp_e100/clock_ctrl.cpp b/host/lib/usrp/e100/clock_ctrl.cpp
index f1b29840a..6acb13528 100644
--- a/host/lib/usrp/usrp_e100/clock_ctrl.cpp
+++ b/host/lib/usrp/e100/clock_ctrl.cpp
@@ -21,7 +21,7 @@
#include <uhd/utils/log.hpp>
#include <uhd/utils/assert_has.hpp>
#include <boost/cstdint.hpp>
-#include "usrp_e100_regs.hpp" //spi slave constants
+#include "e100_regs.hpp" //spi slave constants
#include <boost/assign/list_of.hpp>
#include <boost/foreach.hpp>
#include <boost/format.hpp>
@@ -165,13 +165,19 @@ static clock_settings_type get_clock_settings(double rate){
/***********************************************************************
* Clock Control Implementation
**********************************************************************/
-class usrp_e100_clock_ctrl_impl : public usrp_e100_clock_ctrl{
+class e100_clock_ctrl_impl : public e100_clock_ctrl{
public:
- usrp_e100_clock_ctrl_impl(usrp_e100_iface::sptr iface, double master_clock_rate){
+ e100_clock_ctrl_impl(spi_iface::sptr iface, double master_clock_rate){
_iface = iface;
_chan_rate = 0.0;
_out_rate = 0.0;
+ //perform soft-reset
+ _ad9522_regs.soft_reset = 1;
+ this->send_reg(0x000);
+ this->latch_regs();
+ _ad9522_regs.soft_reset = 0;
+
//init the clock gen registers
//Note: out0 should already be clocking the FPGA or this isnt going to work
_ad9522_regs.sdo_active = ad9522_regs_t::SDO_ACTIVE_SDO_SDIO;
@@ -192,7 +198,7 @@ public:
this->enable_tx_dboard_clock(false);
}
- ~usrp_e100_clock_ctrl_impl(void){
+ ~e100_clock_ctrl_impl(void){
this->enable_test_clock(ENABLE_THE_TEST_OUT);
this->enable_rx_dboard_clock(false);
this->enable_tx_dboard_clock(false);
@@ -288,10 +294,8 @@ public:
if (_out_rate == rate) return;
if (rate == 61.44e6) set_clock_settings_with_external_vcxo(rate);
else set_clock_settings_with_internal_vco(rate);
- //clock rate changed! update dboard clocks and FPGA ticks per second
set_rx_dboard_clock_rate(rate);
set_tx_dboard_clock_rate(rate);
- _iface->poke32(UE_REG_TIME64_TPS, boost::uint32_t(get_fpga_clock_rate()));
}
double get_fpga_clock_rate(void){
@@ -415,7 +419,7 @@ public:
}
private:
- usrp_e100_iface::sptr _iface;
+ spi_iface::sptr _iface;
ad9522_regs_t _ad9522_regs;
double _out_rate; //rate at the fpga and codec
double _chan_rate; //rate before final dividers
@@ -437,8 +441,6 @@ private:
}
void calibrate_now(void){
- set_ignore_sync_fpga_plus_codec(false); //want vco cal to sync
-
//vco calibration routine:
_ad9522_regs.vco_calibration_now = 0;
this->send_reg(0x18);
@@ -467,20 +469,9 @@ private:
_ad9522_regs.get_read_reg(addr), 24
);
_ad9522_regs.set_reg(addr, reg);
- if (_ad9522_regs.digital_lock_detect) goto finalize;
+ if (_ad9522_regs.digital_lock_detect) return;
}
UHD_MSG(error) << "USRP-E100 clock control: lock detection timeout" << std::endl;
- finalize:
-
- set_ignore_sync_fpga_plus_codec(true); //never loose sync between these two
- }
-
- void set_ignore_sync_fpga_plus_codec(bool enb){
- _ad9522_regs.divider0_ignore_sync = (enb)?1:0; // master FPGA clock ignores sync (always on, cannot be disabled by sync pulse)
- _ad9522_regs.divider1_ignore_sync = (enb)?1:0; // codec clock ignores sync (always on, cannot be disabled by sync pulse)
- this->send_reg(0x191);
- this->send_reg(0x194);
- this->latch_regs();
}
void soft_sync(void){
@@ -514,6 +505,6 @@ private:
/***********************************************************************
* Clock Control Make
**********************************************************************/
-usrp_e100_clock_ctrl::sptr usrp_e100_clock_ctrl::make(usrp_e100_iface::sptr iface, double master_clock_rate){
- return sptr(new usrp_e100_clock_ctrl_impl(iface, master_clock_rate));
+e100_clock_ctrl::sptr e100_clock_ctrl::make(spi_iface::sptr iface, double master_clock_rate){
+ return sptr(new e100_clock_ctrl_impl(iface, master_clock_rate));
}
diff --git a/host/lib/usrp/usrp_e100/clock_ctrl.hpp b/host/lib/usrp/e100/clock_ctrl.hpp
index 6f16bc6ed..7c16649d3 100644
--- a/host/lib/usrp/usrp_e100/clock_ctrl.hpp
+++ b/host/lib/usrp/e100/clock_ctrl.hpp
@@ -18,7 +18,7 @@
#ifndef INCLUDED_USRP_E100_CLOCK_CTRL_HPP
#define INCLUDED_USRP_E100_CLOCK_CTRL_HPP
-#include "usrp_e100_iface.hpp"
+#include <uhd/types/serial.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/utility.hpp>
#include <vector>
@@ -28,17 +28,17 @@
* - Setup system clocks.
* - Disable/enable clock lines.
*/
-class usrp_e100_clock_ctrl : boost::noncopyable{
+class e100_clock_ctrl : boost::noncopyable{
public:
- typedef boost::shared_ptr<usrp_e100_clock_ctrl> sptr;
+ typedef boost::shared_ptr<e100_clock_ctrl> sptr;
/*!
* Make a new clock control object.
- * \param iface the usrp_e100 iface object
+ * \param iface the spi iface object
* \param master clock rate the FPGA rate
* \return the clock control object
*/
- static sptr make(usrp_e100_iface::sptr iface, double master_clock_rate);
+ static sptr make(uhd::spi_iface::sptr iface, double master_clock_rate);
/*!
* Set the rate of the fpga clock line.
diff --git a/host/lib/usrp/usrp_e100/codec_ctrl.cpp b/host/lib/usrp/e100/codec_ctrl.cpp
index 43ad94a88..6efeb10e8 100644
--- a/host/lib/usrp/usrp_e100/codec_ctrl.cpp
+++ b/host/lib/usrp/e100/codec_ctrl.cpp
@@ -24,22 +24,22 @@
#include <boost/cstdint.hpp>
#include <boost/tuple/tuple.hpp>
#include <boost/math/special_functions/round.hpp>
-#include "usrp_e100_regs.hpp" //spi slave constants
+#include "e100_regs.hpp" //spi slave constants
#include <boost/assign/list_of.hpp>
using namespace uhd;
-const gain_range_t usrp_e100_codec_ctrl::tx_pga_gain_range(-20, 0, double(0.1));
-const gain_range_t usrp_e100_codec_ctrl::rx_pga_gain_range(0, 20, 1);
+const gain_range_t e100_codec_ctrl::tx_pga_gain_range(-20, 0, double(0.1));
+const gain_range_t e100_codec_ctrl::rx_pga_gain_range(0, 20, 1);
/***********************************************************************
* Codec Control Implementation
**********************************************************************/
-class usrp_e100_codec_ctrl_impl : public usrp_e100_codec_ctrl{
+class e100_codec_ctrl_impl : public e100_codec_ctrl{
public:
//structors
- usrp_e100_codec_ctrl_impl(usrp_e100_iface::sptr iface);
- ~usrp_e100_codec_ctrl_impl(void);
+ e100_codec_ctrl_impl(spi_iface::sptr iface);
+ ~e100_codec_ctrl_impl(void);
//aux adc and dac control
double read_aux_adc(aux_adc_t which);
@@ -52,7 +52,7 @@ public:
double get_rx_pga_gain(char);
private:
- usrp_e100_iface::sptr _iface;
+ spi_iface::sptr _iface;
ad9862_regs_t _ad9862_regs;
void send_reg(boost::uint8_t addr);
void recv_reg(boost::uint8_t addr);
@@ -61,7 +61,7 @@ private:
/***********************************************************************
* Codec Control Structors
**********************************************************************/
-usrp_e100_codec_ctrl_impl::usrp_e100_codec_ctrl_impl(usrp_e100_iface::sptr iface){
+e100_codec_ctrl_impl::e100_codec_ctrl_impl(spi_iface::sptr iface){
_iface = iface;
//soft reset
@@ -116,7 +116,7 @@ usrp_e100_codec_ctrl_impl::usrp_e100_codec_ctrl_impl(usrp_e100_iface::sptr iface
this->send_reg(34);
}
-usrp_e100_codec_ctrl_impl::~usrp_e100_codec_ctrl_impl(void){
+e100_codec_ctrl_impl::~e100_codec_ctrl_impl(void){
//set aux dacs to zero
this->write_aux_dac(AUX_DAC_A, 0);
this->write_aux_dac(AUX_DAC_B, 0);
@@ -136,19 +136,19 @@ usrp_e100_codec_ctrl_impl::~usrp_e100_codec_ctrl_impl(void){
**********************************************************************/
static const int mtpgw = 255; //maximum tx pga gain word
-void usrp_e100_codec_ctrl_impl::set_tx_pga_gain(double gain){
+void e100_codec_ctrl_impl::set_tx_pga_gain(double gain){
int gain_word = int(mtpgw*(gain - tx_pga_gain_range.start())/(tx_pga_gain_range.stop() - tx_pga_gain_range.start()));
_ad9862_regs.tx_pga_gain = uhd::clip(gain_word, 0, mtpgw);
this->send_reg(16);
}
-double usrp_e100_codec_ctrl_impl::get_tx_pga_gain(void){
+double e100_codec_ctrl_impl::get_tx_pga_gain(void){
return (_ad9862_regs.tx_pga_gain*(tx_pga_gain_range.stop() - tx_pga_gain_range.start())/mtpgw) + tx_pga_gain_range.start();
}
static const int mrpgw = 0x14; //maximum rx pga gain word
-void usrp_e100_codec_ctrl_impl::set_rx_pga_gain(double gain, char which){
+void e100_codec_ctrl_impl::set_rx_pga_gain(double gain, char which){
int gain_word = int(mrpgw*(gain - rx_pga_gain_range.start())/(rx_pga_gain_range.stop() - rx_pga_gain_range.start()));
gain_word = uhd::clip(gain_word, 0, mrpgw);
switch(which){
@@ -164,7 +164,7 @@ void usrp_e100_codec_ctrl_impl::set_rx_pga_gain(double gain, char which){
}
}
-double usrp_e100_codec_ctrl_impl::get_rx_pga_gain(char which){
+double e100_codec_ctrl_impl::get_rx_pga_gain(char which){
int gain_word;
switch(which){
case 'A': gain_word = _ad9862_regs.rx_pga_a; break;
@@ -181,7 +181,7 @@ static double aux_adc_to_volts(boost::uint8_t high, boost::uint8_t low){
return double((boost::uint16_t(high) << 2) | low)*3.3/0x3ff;
}
-double usrp_e100_codec_ctrl_impl::read_aux_adc(aux_adc_t which){
+double e100_codec_ctrl_impl::read_aux_adc(aux_adc_t which){
switch(which){
case AUX_ADC_A1:
_ad9862_regs.select_a = ad9862_regs_t::SELECT_A_AUX_ADC1;
@@ -217,7 +217,7 @@ double usrp_e100_codec_ctrl_impl::read_aux_adc(aux_adc_t which){
/***********************************************************************
* Codec Control AUX DAC Methods
**********************************************************************/
-void usrp_e100_codec_ctrl_impl::write_aux_dac(aux_dac_t which, double volts){
+void e100_codec_ctrl_impl::write_aux_dac(aux_dac_t which, double volts){
//special case for aux dac d (aka sigma delta word)
if (which == AUX_DAC_D){
boost::uint16_t dac_word = uhd::clip(boost::math::iround(volts*0xfff/3.3), 0, 0xfff);
@@ -250,7 +250,7 @@ void usrp_e100_codec_ctrl_impl::write_aux_dac(aux_dac_t which, double volts){
/***********************************************************************
* Codec Control SPI Methods
**********************************************************************/
-void usrp_e100_codec_ctrl_impl::send_reg(boost::uint8_t addr){
+void e100_codec_ctrl_impl::send_reg(boost::uint8_t addr){
boost::uint32_t reg = _ad9862_regs.get_write_reg(addr);
UHD_LOGV(often) << "codec control write reg: " << std::hex << reg << std::endl;
_iface->write_spi(
@@ -260,7 +260,7 @@ void usrp_e100_codec_ctrl_impl::send_reg(boost::uint8_t addr){
);
}
-void usrp_e100_codec_ctrl_impl::recv_reg(boost::uint8_t addr){
+void e100_codec_ctrl_impl::recv_reg(boost::uint8_t addr){
boost::uint32_t reg = _ad9862_regs.get_read_reg(addr);
UHD_LOGV(often) << "codec control read reg: " << std::hex << reg << std::endl;
boost::uint32_t ret = _iface->read_spi(
@@ -275,6 +275,6 @@ void usrp_e100_codec_ctrl_impl::recv_reg(boost::uint8_t addr){
/***********************************************************************
* Codec Control Make
**********************************************************************/
-usrp_e100_codec_ctrl::sptr usrp_e100_codec_ctrl::make(usrp_e100_iface::sptr iface){
- return sptr(new usrp_e100_codec_ctrl_impl(iface));
+e100_codec_ctrl::sptr e100_codec_ctrl::make(spi_iface::sptr iface){
+ return sptr(new e100_codec_ctrl_impl(iface));
}
diff --git a/host/lib/usrp/usrp_e100/codec_ctrl.hpp b/host/lib/usrp/e100/codec_ctrl.hpp
index 05d7aab38..707f6f521 100644
--- a/host/lib/usrp/usrp_e100/codec_ctrl.hpp
+++ b/host/lib/usrp/e100/codec_ctrl.hpp
@@ -18,7 +18,7 @@
#ifndef INCLUDED_USRP_E100_CODEC_CTRL_HPP
#define INCLUDED_USRP_E100_CODEC_CTRL_HPP
-#include "usrp_e100_iface.hpp"
+#include <uhd/types/serial.hpp>
#include <uhd/types/ranges.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/utility.hpp>
@@ -28,19 +28,19 @@
* - Init/power down codec.
* - Read aux adc, write aux dac.
*/
-class usrp_e100_codec_ctrl : boost::noncopyable{
+class e100_codec_ctrl : boost::noncopyable{
public:
- typedef boost::shared_ptr<usrp_e100_codec_ctrl> sptr;
+ typedef boost::shared_ptr<e100_codec_ctrl> sptr;
static const uhd::gain_range_t tx_pga_gain_range;
static const uhd::gain_range_t rx_pga_gain_range;
/*!
* Make a new codec control object.
- * \param iface the usrp_e100 iface object
+ * \param iface the spi iface object
* \return the codec control object
*/
- static sptr make(usrp_e100_iface::sptr iface);
+ static sptr make(uhd::spi_iface::sptr iface);
//! aux adc identifier constants
enum aux_adc_t{
diff --git a/host/lib/usrp/usrp_e100/dboard_iface.cpp b/host/lib/usrp/e100/dboard_iface.cpp
index 61b5a1c92..d45577bd9 100644
--- a/host/lib/usrp/usrp_e100/dboard_iface.cpp
+++ b/host/lib/usrp/e100/dboard_iface.cpp
@@ -15,8 +15,9 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
-#include "usrp_e100_iface.hpp"
-#include "usrp_e100_regs.hpp"
+#include "wb_iface.hpp"
+#include <uhd/types/serial.hpp>
+#include "e100_regs.hpp"
#include "clock_ctrl.hpp"
#include "codec_ctrl.hpp"
#include <uhd/usrp/dboard_iface.hpp>
@@ -29,15 +30,19 @@ using namespace uhd;
using namespace uhd::usrp;
using namespace boost::assign;
-class usrp_e100_dboard_iface : public dboard_iface{
+class e100_dboard_iface : public dboard_iface{
public:
- usrp_e100_dboard_iface(
- usrp_e100_iface::sptr iface,
- usrp_e100_clock_ctrl::sptr clock,
- usrp_e100_codec_ctrl::sptr codec
+ e100_dboard_iface(
+ wb_iface::sptr wb_iface,
+ i2c_iface::sptr i2c_iface,
+ spi_iface::sptr spi_iface,
+ e100_clock_ctrl::sptr clock,
+ e100_codec_ctrl::sptr codec
){
- _iface = iface;
+ _wb_iface = wb_iface;
+ _i2c_iface = i2c_iface;
+ _spi_iface = spi_iface;
_clock = clock;
_codec = codec;
@@ -45,11 +50,11 @@ public:
this->set_clock_rate(UNIT_RX, _clock->get_fpga_clock_rate());
this->set_clock_rate(UNIT_TX, _clock->get_fpga_clock_rate());
- _iface->poke16(UE_REG_GPIO_RX_DBG, 0);
- _iface->poke16(UE_REG_GPIO_TX_DBG, 0);
+ _wb_iface->poke16(E100_REG_GPIO_RX_DBG, 0);
+ _wb_iface->poke16(E100_REG_GPIO_TX_DBG, 0);
}
- ~usrp_e100_dboard_iface(void){
+ ~e100_dboard_iface(void){
/* NOP */
}
@@ -94,33 +99,37 @@ public:
double get_codec_rate(unit_t);
private:
- usrp_e100_iface::sptr _iface;
- usrp_e100_clock_ctrl::sptr _clock;
- usrp_e100_codec_ctrl::sptr _codec;
+ wb_iface::sptr _wb_iface;
+ i2c_iface::sptr _i2c_iface;
+ spi_iface::sptr _spi_iface;
+ e100_clock_ctrl::sptr _clock;
+ e100_codec_ctrl::sptr _codec;
};
/***********************************************************************
* Make Function
**********************************************************************/
-dboard_iface::sptr make_usrp_e100_dboard_iface(
- usrp_e100_iface::sptr iface,
- usrp_e100_clock_ctrl::sptr clock,
- usrp_e100_codec_ctrl::sptr codec
+dboard_iface::sptr make_e100_dboard_iface(
+ wb_iface::sptr wb_iface,
+ i2c_iface::sptr i2c_iface,
+ spi_iface::sptr spi_iface,
+ e100_clock_ctrl::sptr clock,
+ e100_codec_ctrl::sptr codec
){
- return dboard_iface::sptr(new usrp_e100_dboard_iface(iface, clock, codec));
+ return dboard_iface::sptr(new e100_dboard_iface(wb_iface, i2c_iface, spi_iface, clock, codec));
}
/***********************************************************************
* Clock Rates
**********************************************************************/
-void usrp_e100_dboard_iface::set_clock_rate(unit_t unit, double rate){
+void e100_dboard_iface::set_clock_rate(unit_t unit, double rate){
switch(unit){
case UNIT_RX: return _clock->set_rx_dboard_clock_rate(rate);
case UNIT_TX: return _clock->set_tx_dboard_clock_rate(rate);
}
}
-std::vector<double> usrp_e100_dboard_iface::get_clock_rates(unit_t unit){
+std::vector<double> e100_dboard_iface::get_clock_rates(unit_t unit){
switch(unit){
case UNIT_RX: return _clock->get_rx_dboard_clock_rates();
case UNIT_TX: return _clock->get_tx_dboard_clock_rates();
@@ -128,7 +137,7 @@ std::vector<double> usrp_e100_dboard_iface::get_clock_rates(unit_t unit){
}
}
-double usrp_e100_dboard_iface::get_clock_rate(unit_t unit){
+double e100_dboard_iface::get_clock_rate(unit_t unit){
switch(unit){
case UNIT_RX: return _clock->get_rx_clock_rate();
case UNIT_TX: return _clock->get_tx_clock_rate();
@@ -136,72 +145,72 @@ double usrp_e100_dboard_iface::get_clock_rate(unit_t unit){
UHD_THROW_INVALID_CODE_PATH();
}
-void usrp_e100_dboard_iface::set_clock_enabled(unit_t unit, bool enb){
+void e100_dboard_iface::set_clock_enabled(unit_t unit, bool enb){
switch(unit){
case UNIT_RX: return _clock->enable_rx_dboard_clock(enb);
case UNIT_TX: return _clock->enable_tx_dboard_clock(enb);
}
}
-double usrp_e100_dboard_iface::get_codec_rate(unit_t){
+double e100_dboard_iface::get_codec_rate(unit_t){
return _clock->get_fpga_clock_rate();
}
/***********************************************************************
* GPIO
**********************************************************************/
-void usrp_e100_dboard_iface::_set_pin_ctrl(unit_t unit, boost::uint16_t value){
+void e100_dboard_iface::_set_pin_ctrl(unit_t unit, boost::uint16_t value){
UHD_ASSERT_THROW(GPIO_SEL_ATR == 1); //make this assumption
switch(unit){
- case UNIT_RX: _iface->poke16(UE_REG_GPIO_RX_SEL, value); return;
- case UNIT_TX: _iface->poke16(UE_REG_GPIO_TX_SEL, value); return;
+ case UNIT_RX: _wb_iface->poke16(E100_REG_GPIO_RX_SEL, value); return;
+ case UNIT_TX: _wb_iface->poke16(E100_REG_GPIO_TX_SEL, value); return;
}
}
-void usrp_e100_dboard_iface::_set_gpio_ddr(unit_t unit, boost::uint16_t value){
+void e100_dboard_iface::_set_gpio_ddr(unit_t unit, boost::uint16_t value){
switch(unit){
- case UNIT_RX: _iface->poke16(UE_REG_GPIO_RX_DDR, value); return;
- case UNIT_TX: _iface->poke16(UE_REG_GPIO_TX_DDR, value); return;
+ case UNIT_RX: _wb_iface->poke16(E100_REG_GPIO_RX_DDR, value); return;
+ case UNIT_TX: _wb_iface->poke16(E100_REG_GPIO_TX_DDR, value); return;
}
}
-void usrp_e100_dboard_iface::_set_gpio_out(unit_t unit, boost::uint16_t value){
+void e100_dboard_iface::_set_gpio_out(unit_t unit, boost::uint16_t value){
switch(unit){
- case UNIT_RX: _iface->poke16(UE_REG_GPIO_RX_IO, value); return;
- case UNIT_TX: _iface->poke16(UE_REG_GPIO_TX_IO, value); return;
+ case UNIT_RX: _wb_iface->poke16(E100_REG_GPIO_RX_IO, value); return;
+ case UNIT_TX: _wb_iface->poke16(E100_REG_GPIO_TX_IO, value); return;
}
}
-boost::uint16_t usrp_e100_dboard_iface::read_gpio(unit_t unit){
+boost::uint16_t e100_dboard_iface::read_gpio(unit_t unit){
switch(unit){
- case UNIT_RX: return _iface->peek16(UE_REG_GPIO_RX_IO);
- case UNIT_TX: return _iface->peek16(UE_REG_GPIO_TX_IO);
+ case UNIT_RX: return _wb_iface->peek16(E100_REG_GPIO_RX_IO);
+ case UNIT_TX: return _wb_iface->peek16(E100_REG_GPIO_TX_IO);
default: UHD_THROW_INVALID_CODE_PATH();
}
}
-void usrp_e100_dboard_iface::_set_atr_reg(unit_t unit, atr_reg_t atr, boost::uint16_t value){
+void e100_dboard_iface::_set_atr_reg(unit_t unit, atr_reg_t atr, boost::uint16_t value){
//define mapping of unit to atr regs to register address
static const uhd::dict<
unit_t, uhd::dict<atr_reg_t, boost::uint32_t>
> unit_to_atr_to_addr = map_list_of
(UNIT_RX, map_list_of
- (ATR_REG_IDLE, UE_REG_ATR_IDLE_RXSIDE)
- (ATR_REG_TX_ONLY, UE_REG_ATR_INTX_RXSIDE)
- (ATR_REG_RX_ONLY, UE_REG_ATR_INRX_RXSIDE)
- (ATR_REG_FULL_DUPLEX, UE_REG_ATR_FULL_RXSIDE)
+ (ATR_REG_IDLE, E100_REG_ATR_IDLE_RXSIDE)
+ (ATR_REG_TX_ONLY, E100_REG_ATR_INTX_RXSIDE)
+ (ATR_REG_RX_ONLY, E100_REG_ATR_INRX_RXSIDE)
+ (ATR_REG_FULL_DUPLEX, E100_REG_ATR_FULL_RXSIDE)
)
(UNIT_TX, map_list_of
- (ATR_REG_IDLE, UE_REG_ATR_IDLE_TXSIDE)
- (ATR_REG_TX_ONLY, UE_REG_ATR_INTX_TXSIDE)
- (ATR_REG_RX_ONLY, UE_REG_ATR_INRX_TXSIDE)
- (ATR_REG_FULL_DUPLEX, UE_REG_ATR_FULL_TXSIDE)
+ (ATR_REG_IDLE, E100_REG_ATR_IDLE_TXSIDE)
+ (ATR_REG_TX_ONLY, E100_REG_ATR_INTX_TXSIDE)
+ (ATR_REG_RX_ONLY, E100_REG_ATR_INRX_TXSIDE)
+ (ATR_REG_FULL_DUPLEX, E100_REG_ATR_FULL_TXSIDE)
)
;
- _iface->poke16(unit_to_atr_to_addr[unit][atr], value);
+ _wb_iface->poke16(unit_to_atr_to_addr[unit][atr], value);
}
-void usrp_e100_dboard_iface::set_gpio_debug(unit_t unit, int which){
+void e100_dboard_iface::set_gpio_debug(unit_t unit, int which){
//set this unit to all outputs
this->set_gpio_ddr(unit, 0xffff);
@@ -213,13 +222,13 @@ void usrp_e100_dboard_iface::set_gpio_debug(unit_t unit, int which){
//set the debug on and which debug selection
switch(unit){
case UNIT_RX:
- _iface->poke16(UE_REG_GPIO_RX_DBG, 0xffff);
- _iface->poke16(UE_REG_GPIO_RX_SEL, dbg_sels);
+ _wb_iface->poke16(E100_REG_GPIO_RX_DBG, 0xffff);
+ _wb_iface->poke16(E100_REG_GPIO_RX_SEL, dbg_sels);
return;
case UNIT_TX:
- _iface->poke16(UE_REG_GPIO_TX_DBG, 0xffff);
- _iface->poke16(UE_REG_GPIO_TX_SEL, dbg_sels);
+ _wb_iface->poke16(E100_REG_GPIO_TX_DBG, 0xffff);
+ _wb_iface->poke16(E100_REG_GPIO_TX_SEL, dbg_sels);
return;
}
}
@@ -240,60 +249,60 @@ static boost::uint32_t unit_to_otw_spi_dev(dboard_iface::unit_t unit){
UHD_THROW_INVALID_CODE_PATH();
}
-void usrp_e100_dboard_iface::write_spi(
+void e100_dboard_iface::write_spi(
unit_t unit,
const spi_config_t &config,
boost::uint32_t data,
size_t num_bits
){
- _iface->write_spi(unit_to_otw_spi_dev(unit), config, data, num_bits);
+ _spi_iface->write_spi(unit_to_otw_spi_dev(unit), config, data, num_bits);
}
-boost::uint32_t usrp_e100_dboard_iface::read_write_spi(
+boost::uint32_t e100_dboard_iface::read_write_spi(
unit_t unit,
const spi_config_t &config,
boost::uint32_t data,
size_t num_bits
){
- return _iface->read_spi(unit_to_otw_spi_dev(unit), config, data, num_bits);
+ return _spi_iface->read_spi(unit_to_otw_spi_dev(unit), config, data, num_bits);
}
/***********************************************************************
* I2C
**********************************************************************/
-void usrp_e100_dboard_iface::write_i2c(boost::uint8_t addr, const byte_vector_t &bytes){
- return _iface->write_i2c(addr, bytes);
+void e100_dboard_iface::write_i2c(boost::uint8_t addr, const byte_vector_t &bytes){
+ return _i2c_iface->write_i2c(addr, bytes);
}
-byte_vector_t usrp_e100_dboard_iface::read_i2c(boost::uint8_t addr, size_t num_bytes){
- return _iface->read_i2c(addr, num_bytes);
+byte_vector_t e100_dboard_iface::read_i2c(boost::uint8_t addr, size_t num_bytes){
+ return _i2c_iface->read_i2c(addr, num_bytes);
}
/***********************************************************************
* Aux DAX/ADC
**********************************************************************/
-void usrp_e100_dboard_iface::write_aux_dac(dboard_iface::unit_t, aux_dac_t which, double value){
+void e100_dboard_iface::write_aux_dac(dboard_iface::unit_t, aux_dac_t which, double value){
//same aux dacs for each unit
- static const uhd::dict<aux_dac_t, usrp_e100_codec_ctrl::aux_dac_t> which_to_aux_dac = map_list_of
- (AUX_DAC_A, usrp_e100_codec_ctrl::AUX_DAC_A)
- (AUX_DAC_B, usrp_e100_codec_ctrl::AUX_DAC_B)
- (AUX_DAC_C, usrp_e100_codec_ctrl::AUX_DAC_C)
- (AUX_DAC_D, usrp_e100_codec_ctrl::AUX_DAC_D)
+ static const uhd::dict<aux_dac_t, e100_codec_ctrl::aux_dac_t> which_to_aux_dac = map_list_of
+ (AUX_DAC_A, e100_codec_ctrl::AUX_DAC_A)
+ (AUX_DAC_B, e100_codec_ctrl::AUX_DAC_B)
+ (AUX_DAC_C, e100_codec_ctrl::AUX_DAC_C)
+ (AUX_DAC_D, e100_codec_ctrl::AUX_DAC_D)
;
_codec->write_aux_dac(which_to_aux_dac[which], value);
}
-double usrp_e100_dboard_iface::read_aux_adc(dboard_iface::unit_t unit, aux_adc_t which){
+double e100_dboard_iface::read_aux_adc(dboard_iface::unit_t unit, aux_adc_t which){
static const uhd::dict<
- unit_t, uhd::dict<aux_adc_t, usrp_e100_codec_ctrl::aux_adc_t>
+ unit_t, uhd::dict<aux_adc_t, e100_codec_ctrl::aux_adc_t>
> unit_to_which_to_aux_adc = map_list_of
(UNIT_RX, map_list_of
- (AUX_ADC_A, usrp_e100_codec_ctrl::AUX_ADC_A1)
- (AUX_ADC_B, usrp_e100_codec_ctrl::AUX_ADC_B1)
+ (AUX_ADC_A, e100_codec_ctrl::AUX_ADC_A1)
+ (AUX_ADC_B, e100_codec_ctrl::AUX_ADC_B1)
)
(UNIT_TX, map_list_of
- (AUX_ADC_A, usrp_e100_codec_ctrl::AUX_ADC_A2)
- (AUX_ADC_B, usrp_e100_codec_ctrl::AUX_ADC_B2)
+ (AUX_ADC_A, e100_codec_ctrl::AUX_ADC_A2)
+ (AUX_ADC_B, e100_codec_ctrl::AUX_ADC_B2)
)
;
return _codec->read_aux_adc(unit_to_which_to_aux_adc[unit][which]);
diff --git a/host/lib/usrp/usrp_e100/usrp_e100_iface.cpp b/host/lib/usrp/e100/e100_ctrl.cpp
index 55446da63..87f7855d3 100644
--- a/host/lib/usrp/usrp_e100/usrp_e100_iface.cpp
+++ b/host/lib/usrp/e100/e100_ctrl.cpp
@@ -1,5 +1,5 @@
//
-// Copyright 2010-2011 Ettus Research LLC
+// Copyright 2011 Ettus Research LLC
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -15,24 +15,106 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
-#include "usrp_e100_iface.hpp"
-#include "usrp_e100_regs.hpp"
+#include "e100_ctrl.hpp"
+#include "e100_regs.hpp"
#include <uhd/exception.hpp>
+#include <uhd/utils/msg.hpp>
#include <sys/ioctl.h> //ioctl
#include <fcntl.h> //open, close
#include <linux/usrp_e.h> //ioctl structures and constants
-#include <boost/format.hpp>
+#include <boost/thread/thread.hpp> //sleep
#include <boost/thread/mutex.hpp>
-#include <linux/i2c-dev.h>
-#include <linux/i2c.h>
-#include <stdexcept>
+#include <boost/format.hpp>
+#include <fstream>
using namespace uhd;
-using namespace uhd::usrp;
+
+/***********************************************************************
+ * Sysfs GPIO wrapper class
+ **********************************************************************/
+class gpio{
+public:
+ gpio(const int num, const std::string &dir) : _num(num){
+ this->set_xport("export");
+ this->set_dir(dir);
+ _value_file.open(str(boost::format("/sys/class/gpio/gpio%d/value") % num).c_str(), std::ios_base::in | std::ios_base::out);
+ }
+ ~gpio(void){
+ _value_file.close();
+ this->set_dir("in");
+ this->set_xport("unexport");
+ }
+ void operator()(const int val){
+ _value_file << val << std::endl << std::flush;
+ }
+ int operator()(void){
+ std::string val;
+ std::getline(_value_file, val);
+ _value_file.seekg(0);
+ return int(val.at(0) - '0') & 0x1;
+ }
+private:
+ void set_xport(const std::string &xport){
+ std::ofstream export_file(("/sys/class/gpio/" + xport).c_str());
+ export_file << _num << std::endl << std::flush;
+ export_file.close();
+ }
+ void set_dir(const std::string &dir){
+ std::ofstream dir_file(str(boost::format("/sys/class/gpio/gpio%d/direction") % _num).c_str());
+ dir_file << dir << std::endl << std::flush;
+ dir_file.close();
+ }
+ const int _num;
+ std::fstream _value_file;
+};
+
+/***********************************************************************
+ * Aux spi implementation
+ **********************************************************************/
+class aux_spi_iface_impl : public spi_iface{
+public:
+ aux_spi_iface_impl(void):
+ spi_sclk_gpio(65, "out"),
+ spi_sen_gpio(186, "out"),
+ spi_mosi_gpio(145, "out"),
+ spi_miso_gpio(147, "in"){}
+
+ boost::uint32_t transact_spi(
+ int, const spi_config_t &, //not used params
+ boost::uint32_t bits,
+ size_t num_bits,
+ bool readback
+ ){
+ boost::uint32_t rb_bits = 0;
+ this->spi_sen_gpio(0);
+
+ for (size_t i = 0; i < num_bits; i++){
+ this->spi_sclk_gpio(0);
+ this->spi_mosi_gpio((bits >> (num_bits-i-1)) & 0x1);
+ boost::this_thread::sleep(boost::posix_time::microseconds(10));
+ if (readback) rb_bits = (rb_bits << 1) | this->spi_miso_gpio();
+ this->spi_sclk_gpio(1);
+ boost::this_thread::sleep(boost::posix_time::microseconds(10));
+ }
+
+ this->spi_sen_gpio(1);
+ boost::this_thread::sleep(boost::posix_time::microseconds(100));
+ return rb_bits;
+ }
+
+private:
+ gpio spi_sclk_gpio, spi_sen_gpio, spi_mosi_gpio, spi_miso_gpio;
+};
+
+uhd::spi_iface::sptr e100_ctrl::make_aux_spi_iface(void){
+ return uhd::spi_iface::sptr(new aux_spi_iface_impl());
+}
/***********************************************************************
* I2C device node implementation wrapper
**********************************************************************/
+#include <linux/i2c-dev.h>
+#include <linux/i2c.h>
class i2c_dev_iface : public i2c_iface{
public:
i2c_dev_iface(const std::string &node){
@@ -88,10 +170,14 @@ public:
private: int _node_fd;
};
+uhd::i2c_iface::sptr e100_ctrl::make_dev_i2c_iface(const std::string &node){
+ return uhd::i2c_iface::sptr(new i2c_dev_iface(node));
+}
+
/***********************************************************************
- * USRP-E100 interface implementation
+ * USRP-E100 control implementation
**********************************************************************/
-class usrp_e100_iface_impl : public usrp_e100_iface{
+class e100_ctrl_impl : public e100_ctrl{
public:
int get_file_descriptor(void){
@@ -101,9 +187,9 @@ public:
/*******************************************************************
* Structors
******************************************************************/
- usrp_e100_iface_impl(const std::string &node):
- _i2c_dev_iface(i2c_dev_iface("/dev/i2c-3"))
- {
+ e100_ctrl_impl(const std::string &node){
+ UHD_MSG(status) << "Opening device node " << node << "..." << std::endl;
+
//open the device node and check file descriptor
if ((_node_fd = ::open(node.c_str(), O_RDWR)) < 0){
throw uhd::io_error("Failed to open " + node);
@@ -112,17 +198,17 @@ public:
//check the module compatibility number
int module_compat_num = ::ioctl(_node_fd, USRP_E_GET_COMPAT_NUMBER, NULL);
if (module_compat_num != USRP_E_COMPAT_NUMBER){
- throw uhd::runtime_error(str(boost::format(
- "Expected module compatibility number 0x%x, but got 0x%x:\n"
- "The module build is not compatible with the host code build."
- ) % USRP_E_COMPAT_NUMBER % module_compat_num));
- }
+ throw uhd::runtime_error(str(boost::format(
+ "Expected module compatibility number 0x%x, but got 0x%x:\n"
+ "The module build is not compatible with the host code build."
+ ) % USRP_E_COMPAT_NUMBER % module_compat_num));
+ }
- mb_eeprom = mboard_eeprom_t(get_i2c_dev_iface(), mboard_eeprom_t::MAP_E100);
+ //perform a global reset after opening
+ this->poke32(E100_REG_GLOBAL_RESET, 0);
}
- ~usrp_e100_iface_impl(void){
- //close the device node file descriptor
+ ~e100_ctrl_impl(void){
::close(_node_fd);
}
@@ -130,7 +216,7 @@ public:
* IOCTL: provides the communication base for all other calls
******************************************************************/
void ioctl(int request, void *mem){
- boost::mutex::scoped_lock lock(_ctrl_mutex);
+ boost::mutex::scoped_lock lock(_ioctl_mutex);
if (::ioctl(_node_fd, request, mem) < 0){
throw uhd::os_error(str(
@@ -138,18 +224,10 @@ public:
));
}
}
-
- /*******************************************************************
- * I2C device node interface
- ******************************************************************/
- i2c_iface &get_i2c_dev_iface(void){
- return _i2c_dev_iface;
- }
-
/*******************************************************************
* Peek and Poke
******************************************************************/
- void poke32(boost::uint32_t addr, boost::uint32_t value){
+ void poke32(wb_addr_type addr, boost::uint32_t value){
//load the data struct
usrp_e_ctl32 data;
data.offset = addr;
@@ -160,7 +238,7 @@ public:
this->ioctl(USRP_E_WRITE_CTL32, &data);
}
- void poke16(boost::uint32_t addr, boost::uint16_t value){
+ void poke16(wb_addr_type addr, boost::uint16_t value){
//load the data struct
usrp_e_ctl16 data;
data.offset = addr;
@@ -171,7 +249,7 @@ public:
this->ioctl(USRP_E_WRITE_CTL16, &data);
}
- boost::uint32_t peek32(boost::uint32_t addr){
+ boost::uint32_t peek32(wb_addr_type addr){
//load the data struct
usrp_e_ctl32 data;
data.offset = addr;
@@ -183,7 +261,7 @@ public:
return data.buf[0];
}
- boost::uint16_t peek16(boost::uint32_t addr){
+ boost::uint16_t peek16(wb_addr_type addr){
//load the data struct
usrp_e_ctl16 data;
data.offset = addr;
@@ -195,92 +273,14 @@ public:
return data.buf[0];
}
- /*******************************************************************
- * I2C
- ******************************************************************/
- static const size_t max_i2c_data_bytes = 10;
-
- void write_i2c(boost::uint8_t addr, const byte_vector_t &bytes){
- //allocate some memory for this transaction
- UHD_ASSERT_THROW(bytes.size() <= max_i2c_data_bytes);
- boost::uint8_t mem[sizeof(usrp_e_i2c) + max_i2c_data_bytes];
-
- //load the data struct
- usrp_e_i2c *data = reinterpret_cast<usrp_e_i2c*>(mem);
- data->addr = addr;
- data->len = bytes.size();
- std::copy(bytes.begin(), bytes.end(), data->data);
-
- //call the spi ioctl
- this->ioctl(USRP_E_I2C_WRITE, data);
- }
-
- byte_vector_t read_i2c(boost::uint8_t addr, size_t num_bytes){
- //allocate some memory for this transaction
- UHD_ASSERT_THROW(num_bytes <= max_i2c_data_bytes);
- boost::uint8_t mem[sizeof(usrp_e_i2c) + max_i2c_data_bytes];
-
- //load the data struct
- usrp_e_i2c *data = reinterpret_cast<usrp_e_i2c*>(mem);
- data->addr = addr;
- data->len = num_bytes;
-
- //call the spi ioctl
- this->ioctl(USRP_E_I2C_READ, data);
-
- //unload the data
- byte_vector_t bytes(data->len);
- UHD_ASSERT_THROW(bytes.size() == num_bytes);
- std::copy(data->data, data->data+bytes.size(), bytes.begin());
- return bytes;
- }
-
- /*******************************************************************
- * SPI
- ******************************************************************/
- boost::uint32_t transact_spi(
- int which_slave,
- const spi_config_t &config,
- boost::uint32_t bits,
- size_t num_bits,
- bool readback
- ){
- //load data struct
- usrp_e_spi data;
- data.readback = (readback)? UE_SPI_TXRX : UE_SPI_TXONLY;
- data.slave = which_slave;
- data.length = num_bits;
- data.data = bits;
-
- //load the flags
- data.flags = 0;
- data.flags |= (config.miso_edge == spi_config_t::EDGE_RISE)? UE_SPI_LATCH_RISE : UE_SPI_LATCH_FALL;
- data.flags |= (config.mosi_edge == spi_config_t::EDGE_RISE)? UE_SPI_PUSH_FALL : UE_SPI_PUSH_RISE;
-
- //call the spi ioctl
- this->ioctl(USRP_E_SPI, &data);
-
- //unload the data
- return data.data;
- }
-
- void write_uart(boost::uint8_t, const std::string &) {
- throw uhd::not_implemented_error("Unhandled command write_uart()");
- }
-
- std::string read_uart(boost::uint8_t) {
- throw uhd::not_implemented_error("Unhandled command read_uart()");
- }
-
private:
int _node_fd;
- i2c_dev_iface _i2c_dev_iface;
- boost::mutex _ctrl_mutex;
+ boost::mutex _ioctl_mutex;
};
/***********************************************************************
* Public Make Function
**********************************************************************/
-usrp_e100_iface::sptr usrp_e100_iface::make(const std::string &node){
- return sptr(new usrp_e100_iface_impl(node));
+e100_ctrl::sptr e100_ctrl::make(const std::string &node){
+ return sptr(new e100_ctrl_impl(node));
}
diff --git a/host/lib/usrp/e100/e100_ctrl.hpp b/host/lib/usrp/e100/e100_ctrl.hpp
new file mode 100644
index 000000000..8520ea595
--- /dev/null
+++ b/host/lib/usrp/e100/e100_ctrl.hpp
@@ -0,0 +1,45 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// 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_B100_CTRL_HPP
+#define INCLUDED_B100_CTRL_HPP
+
+#include "wb_iface.hpp"
+#include <uhd/types/serial.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/utility.hpp>
+
+class e100_ctrl : boost::noncopyable, public wb_iface{
+public:
+ typedef boost::shared_ptr<e100_ctrl> sptr;
+
+ //! Make a new controller for E100
+ static sptr make(const std::string &node);
+
+ //! Make an i2c iface for the i2c device node
+ static uhd::i2c_iface::sptr make_dev_i2c_iface(const std::string &node);
+
+ //! Make an i2c iface for the i2c device node
+ static uhd::spi_iface::sptr make_aux_spi_iface(void);
+
+ virtual void ioctl(int request, void *mem) = 0;
+
+ virtual int get_file_descriptor(void) = 0;
+
+};
+
+#endif /* INCLUDED_B100_CTRL_HPP */
diff --git a/host/lib/usrp/e100/e100_impl.cpp b/host/lib/usrp/e100/e100_impl.cpp
new file mode 100644
index 000000000..cca4ee9b3
--- /dev/null
+++ b/host/lib/usrp/e100/e100_impl.cpp
@@ -0,0 +1,390 @@
+//
+// Copyright 2010-2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// 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 "e100_impl.hpp"
+#include "e100_regs.hpp"
+#include <uhd/utils/msg.hpp>
+#include <uhd/exception.hpp>
+#include <uhd/utils/static.hpp>
+#include <uhd/utils/images.hpp>
+#include <boost/bind.hpp>
+#include <boost/format.hpp>
+#include <boost/filesystem.hpp>
+#include <boost/functional/hash.hpp>
+#include <boost/assign/list_of.hpp>
+#include <fstream>
+
+using namespace uhd;
+using namespace uhd::usrp;
+namespace fs = boost::filesystem;
+
+////////////////////////////////////////////////////////////////////////
+// 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)
+
+/***********************************************************************
+ * Discovery
+ **********************************************************************/
+static device_addrs_t e100_find(const device_addr_t &hint){
+ device_addrs_t e100_addrs;
+
+ //return an empty list of addresses when type is set to non-usrp-e
+ if (hint.has_key("type") and hint["type"] != "e100") return e100_addrs;
+
+ //device node not provided, assume its 0
+ if (not hint.has_key("node")){
+ device_addr_t new_addr = hint;
+ new_addr["node"] = "/dev/usrp_e0";
+ return e100_find(new_addr);
+ }
+
+ //use the given device node name
+ if (fs::exists(hint["node"])){
+ device_addr_t new_addr;
+ new_addr["type"] = "e100";
+ new_addr["node"] = fs::system_complete(fs::path(hint["node"])).string();
+ try{
+ i2c_iface::sptr i2c_iface = e100_ctrl::make_dev_i2c_iface(E100_I2C_DEV_NODE);
+ const mboard_eeprom_t mb_eeprom(*i2c_iface, mboard_eeprom_t::MAP_E100);
+ new_addr["name"] = mb_eeprom["name"];
+ new_addr["serial"] = mb_eeprom["serial"];
+ }
+ catch(const std::exception &e){
+ new_addr["name"] = "";
+ new_addr["serial"] = "";
+ }
+ if (
+ (not hint.has_key("name") or hint["name"] == new_addr["name"]) and
+ (not hint.has_key("serial") or hint["serial"] == new_addr["serial"])
+ ){
+ e100_addrs.push_back(new_addr);
+ }
+ }
+
+ return e100_addrs;
+}
+
+/***********************************************************************
+ * Make
+ **********************************************************************/
+static size_t hash_fpga_file(const std::string &file_path){
+ size_t hash = 0;
+ std::ifstream file(file_path.c_str());
+ if (not file.good()) throw uhd::io_error("cannot open fpga file for read: " + file_path);
+ while (file.good()) boost::hash_combine(hash, file.get());
+ file.close();
+ return hash;
+}
+
+static device::sptr e100_make(const device_addr_t &device_addr){
+ return device::sptr(new e100_impl(device_addr));
+}
+
+UHD_STATIC_BLOCK(register_e100_device){
+ device::register_device(&e100_find, &e100_make);
+}
+
+/***********************************************************************
+ * Structors
+ **********************************************************************/
+e100_impl::e100_impl(const uhd::device_addr_t &device_addr){
+
+ //setup the main interface into fpga
+ const std::string node = device_addr["node"];
+ _fpga_ctrl = e100_ctrl::make(node);
+
+ //extract the fpga path and compute hash
+ const std::string e100_fpga_image = find_image_path(device_addr.get("fpga", E100_FPGA_FILE_NAME));
+ const boost::uint32_t file_hash = boost::uint32_t(hash_fpga_file(e100_fpga_image));
+
+ //When the hash does not match:
+ // - close the device node
+ // - load the fpga bin file
+ // - re-open the device node
+ if (_fpga_ctrl->peek32(E100_REG_RB_MISC_TEST32) != file_hash){
+ _fpga_ctrl.reset();
+ e100_load_fpga(e100_fpga_image);
+ _fpga_ctrl = e100_ctrl::make(node);
+ }
+
+ //setup clock control here to ensure that the FPGA has a good clock before we continue
+ const double master_clock_rate = device_addr.cast<double>("master_clock_rate", E100_DEFAULT_CLOCK_RATE);
+ _aux_spi_iface = e100_ctrl::make_aux_spi_iface();
+ _clock_ctrl = e100_clock_ctrl::make(_aux_spi_iface, master_clock_rate);
+
+ //Perform wishbone readback tests, these tests also write the hash
+ bool test_fail = false;
+ UHD_MSG(status) << "Performing wishbone readback test... " << std::flush;
+ for (size_t i = 0; i < 100; i++){
+ _fpga_ctrl->poke32(E100_REG_SR_MISC_TEST32, file_hash);
+ test_fail = _fpga_ctrl->peek32(E100_REG_RB_MISC_TEST32) != file_hash;
+ if (test_fail) break; //exit loop on any failure
+ }
+ UHD_MSG(status) << ((test_fail)? " fail" : "pass") << std::endl;
+
+ if (test_fail) UHD_MSG(error) << boost::format(
+ "The FPGA is either clocked improperly\n"
+ "or the FPGA build is not compatible.\n"
+ "Subsequent errors may follow...\n"
+ );
+
+ //check that the compatibility is correct
+ const boost::uint16_t fpga_compat_num = _fpga_ctrl->peek16(E100_REG_MISC_COMPAT);
+ if (fpga_compat_num != E100_FPGA_COMPAT_NUM){
+ throw uhd::runtime_error(str(boost::format(
+ "\nPlease update the FPGA image for your device.\n"
+ "See the application notes for USRP E-Series for instructions.\n"
+ "Expected FPGA compatibility number 0x%x, but got 0x%x:\n"
+ "The FPGA build is not compatible with the host code build."
+ ) % E100_FPGA_COMPAT_NUM % fpga_compat_num));
+ }
+
+ ////////////////////////////////////////////////////////////////////
+ // Create controller objects
+ ////////////////////////////////////////////////////////////////////
+ _fpga_i2c_ctrl = i2c_core_100::make(_fpga_ctrl, E100_REG_SLAVE(3));
+ _fpga_spi_ctrl = spi_core_100::make(_fpga_ctrl, E100_REG_SLAVE(2));
+ _dev_i2c_iface = e100_ctrl::make_dev_i2c_iface(E100_I2C_DEV_NODE);
+ _data_transport = e100_make_mmap_zero_copy(_fpga_ctrl);
+
+ ////////////////////////////////////////////////////////////////////
+ // Initialize the properties tree
+ ////////////////////////////////////////////////////////////////////
+ _tree = property_tree::make();
+ _tree->create<std::string>("/name").set("E-Series Device");
+ const property_tree::path_type mb_path = "/mboards/0";
+ _tree->create<std::string>(mb_path / "name").set("E100 (euewanee)");
+
+ ////////////////////////////////////////////////////////////////////
+ // setup the mboard eeprom
+ ////////////////////////////////////////////////////////////////////
+ const mboard_eeprom_t mb_eeprom(*_dev_i2c_iface, mboard_eeprom_t::MAP_E100);
+ _tree->create<mboard_eeprom_t>(mb_path / "eeprom")
+ .set(mb_eeprom)
+ .subscribe(boost::bind(&e100_impl::set_mb_eeprom, this, _1));
+
+ ////////////////////////////////////////////////////////////////////
+ // create clock control objects
+ ////////////////////////////////////////////////////////////////////
+ //^^^ clock created up top, just reg props here... ^^^
+ _tree->create<double>(mb_path / "tick_rate")
+ .publish(boost::bind(&e100_clock_ctrl::get_fpga_clock_rate, _clock_ctrl))
+ .subscribe(boost::bind(&e100_impl::update_tick_rate, this, _1));
+
+ ////////////////////////////////////////////////////////////////////
+ // create codec control objects
+ ////////////////////////////////////////////////////////////////////
+ _codec_ctrl = e100_codec_ctrl::make(_fpga_spi_ctrl);
+ const property_tree::path_type rx_codec_path = mb_path / "rx_codecs/A";
+ const property_tree::path_type tx_codec_path = mb_path / "tx_codecs/A";
+ _tree->create<std::string>(rx_codec_path / "name").set("ad9522");
+ _tree->create<meta_range_t>(rx_codec_path / "gains/pga/range").set(e100_codec_ctrl::rx_pga_gain_range);
+ _tree->create<double>(rx_codec_path / "gains/pga/value")
+ .coerce(boost::bind(&e100_impl::update_rx_codec_gain, this, _1));
+ _tree->create<std::string>(tx_codec_path / "name").set("ad9522");
+ _tree->create<meta_range_t>(tx_codec_path / "gains/pga/range").set(e100_codec_ctrl::tx_pga_gain_range);
+ _tree->create<double>(tx_codec_path / "gains/pga/value")
+ .subscribe(boost::bind(&e100_codec_ctrl::set_tx_pga_gain, _codec_ctrl, _1))
+ .publish(boost::bind(&e100_codec_ctrl::get_tx_pga_gain, _codec_ctrl));
+
+ ////////////////////////////////////////////////////////////////////
+ // and do the misc mboard sensors
+ ////////////////////////////////////////////////////////////////////
+ //none for now...
+ _tree->create<int>(mb_path / "sensors"); //phony property so this dir exists
+
+ ////////////////////////////////////////////////////////////////////
+ // create frontend control objects
+ ////////////////////////////////////////////////////////////////////
+ _rx_fe = rx_frontend_core_200::make(_fpga_ctrl, E100_REG_SR_ADDR(UE_SR_RX_FRONT));
+ _tx_fe = tx_frontend_core_200::make(_fpga_ctrl, E100_REG_SR_ADDR(UE_SR_TX_FRONT));
+ //TODO lots of properties to expose here for frontends
+ _tree->create<subdev_spec_t>(mb_path / "rx_subdev_spec")
+ .subscribe(boost::bind(&e100_impl::update_rx_subdev_spec, this, _1));
+ _tree->create<subdev_spec_t>(mb_path / "tx_subdev_spec")
+ .subscribe(boost::bind(&e100_impl::update_tx_subdev_spec, this, _1));
+
+ ////////////////////////////////////////////////////////////////////
+ // create rx dsp control objects
+ ////////////////////////////////////////////////////////////////////
+ _rx_dsps.push_back(rx_dsp_core_200::make(
+ _fpga_ctrl, E100_REG_SR_ADDR(UE_SR_RX_DSP0), E100_REG_SR_ADDR(UE_SR_RX_CTRL0), E100_RX_SID_BASE + 0
+ ));
+ _rx_dsps.push_back(rx_dsp_core_200::make(
+ _fpga_ctrl, E100_REG_SR_ADDR(UE_SR_RX_DSP1), E100_REG_SR_ADDR(UE_SR_RX_CTRL1), E100_RX_SID_BASE + 1
+ ));
+ for (size_t dspno = 0; dspno < _rx_dsps.size(); dspno++){
+ _rx_dsps[dspno]->set_link_rate(E100_LINK_RATE_BPS);
+ _tree->access<double>(mb_path / "tick_rate")
+ .subscribe(boost::bind(&rx_dsp_core_200::set_tick_rate, _rx_dsps[dspno], _1));
+ property_tree::path_type rx_dsp_path = mb_path / str(boost::format("rx_dsps/%u") % dspno);
+ _tree->create<double>(rx_dsp_path / "rate/value")
+ .coerce(boost::bind(&rx_dsp_core_200::set_host_rate, _rx_dsps[dspno], _1))
+ .subscribe(boost::bind(&e100_impl::update_rx_samp_rate, this, _1));
+ _tree->create<double>(rx_dsp_path / "freq/value")
+ .coerce(boost::bind(&rx_dsp_core_200::set_freq, _rx_dsps[dspno], _1));
+ _tree->create<meta_range_t>(rx_dsp_path / "freq/range")
+ .publish(boost::bind(&rx_dsp_core_200::get_freq_range, _rx_dsps[dspno]));
+ _tree->create<stream_cmd_t>(rx_dsp_path / "stream_cmd")
+ .subscribe(boost::bind(&rx_dsp_core_200::issue_stream_command, _rx_dsps[dspno], _1));
+ }
+
+ ////////////////////////////////////////////////////////////////////
+ // create tx dsp control objects
+ ////////////////////////////////////////////////////////////////////
+ _tx_dsp = tx_dsp_core_200::make(
+ _fpga_ctrl, E100_REG_SR_ADDR(UE_SR_TX_DSP), E100_REG_SR_ADDR(UE_SR_TX_CTRL), E100_TX_ASYNC_SID
+ );
+ _tx_dsp->set_link_rate(E100_LINK_RATE_BPS);
+ _tree->access<double>(mb_path / "tick_rate")
+ .subscribe(boost::bind(&tx_dsp_core_200::set_tick_rate, _tx_dsp, _1));
+ _tree->create<double>(mb_path / "tx_dsps/0/rate/value")
+ .coerce(boost::bind(&tx_dsp_core_200::set_host_rate, _tx_dsp, _1))
+ .subscribe(boost::bind(&e100_impl::update_tx_samp_rate, this, _1));
+ _tree->create<double>(mb_path / "tx_dsps/0/freq/value")
+ .coerce(boost::bind(&tx_dsp_core_200::set_freq, _tx_dsp, _1));
+ _tree->create<meta_range_t>(mb_path / "tx_dsps/0/freq/range")
+ .publish(boost::bind(&tx_dsp_core_200::get_freq_range, _tx_dsp));
+
+ ////////////////////////////////////////////////////////////////////
+ // create time control objects
+ ////////////////////////////////////////////////////////////////////
+ time64_core_200::readback_bases_type time64_rb_bases;
+ time64_rb_bases.rb_secs_now = E100_REG_RB_TIME_NOW_SECS;
+ time64_rb_bases.rb_ticks_now = E100_REG_RB_TIME_NOW_TICKS;
+ time64_rb_bases.rb_secs_pps = E100_REG_RB_TIME_PPS_SECS;
+ time64_rb_bases.rb_ticks_pps = E100_REG_RB_TIME_PPS_TICKS;
+ _time64 = time64_core_200::make(
+ _fpga_ctrl, E100_REG_SR_ADDR(UE_SR_TIME64), time64_rb_bases
+ );
+ _tree->access<double>(mb_path / "tick_rate")
+ .subscribe(boost::bind(&time64_core_200::set_tick_rate, _time64, _1));
+ _tree->create<time_spec_t>(mb_path / "time/now")
+ .publish(boost::bind(&time64_core_200::get_time_now, _time64))
+ .subscribe(boost::bind(&time64_core_200::set_time_now, _time64, _1));
+ _tree->create<time_spec_t>(mb_path / "time/pps")
+ .publish(boost::bind(&time64_core_200::get_time_last_pps, _time64))
+ .subscribe(boost::bind(&time64_core_200::set_time_next_pps, _time64, _1));
+ //setup time source props
+ _tree->create<std::string>(mb_path / "time_source/value")
+ .subscribe(boost::bind(&time64_core_200::set_time_source, _time64, _1));
+ _tree->create<std::vector<std::string> >(mb_path / "time_source/options")
+ .publish(boost::bind(&time64_core_200::get_time_sources, _time64));
+ //setup reference source props
+ _tree->create<std::string>(mb_path / "clock_source/value")
+ .subscribe(boost::bind(&e100_impl::update_clock_source, this, _1));
+ static const std::vector<std::string> clock_sources = boost::assign::list_of("internal")("external")("auto");
+ _tree->create<std::vector<std::string> >(mb_path / "clock_source/options").set(clock_sources);
+
+ ////////////////////////////////////////////////////////////////////
+ // create dboard control objects
+ ////////////////////////////////////////////////////////////////////
+
+ //read the dboard eeprom to extract the dboard ids
+ dboard_eeprom_t rx_db_eeprom, tx_db_eeprom, gdb_eeprom;
+ rx_db_eeprom.load(*_fpga_i2c_ctrl, I2C_ADDR_RX_DB);
+ tx_db_eeprom.load(*_fpga_i2c_ctrl, I2C_ADDR_TX_DB);
+ gdb_eeprom.load(*_fpga_i2c_ctrl, I2C_ADDR_TX_DB ^ 5);
+
+ //create the properties and register subscribers
+ _tree->create<dboard_eeprom_t>(mb_path / "dboards/A/rx_eeprom")
+ .set(rx_db_eeprom)
+ .subscribe(boost::bind(&e100_impl::set_db_eeprom, this, "rx", _1));
+ _tree->create<dboard_eeprom_t>(mb_path / "dboards/A/tx_eeprom")
+ .set(tx_db_eeprom)
+ .subscribe(boost::bind(&e100_impl::set_db_eeprom, this, "tx", _1));
+ _tree->create<dboard_eeprom_t>(mb_path / "dboards/A/gdb_eeprom")
+ .set(gdb_eeprom)
+ .subscribe(boost::bind(&e100_impl::set_db_eeprom, this, "gdb", _1));
+
+ //create a new dboard interface and manager
+ _dboard_iface = make_e100_dboard_iface(_fpga_ctrl, _fpga_i2c_ctrl, _fpga_spi_ctrl, _clock_ctrl, _codec_ctrl);
+ _tree->create<dboard_iface::sptr>(mb_path / "dboards/A/iface").set(_dboard_iface);
+ _dboard_manager = dboard_manager::make(
+ rx_db_eeprom.id,
+ ((gdb_eeprom.id == dboard_id_t::none())? tx_db_eeprom : gdb_eeprom).id,
+ _dboard_iface
+ );
+ BOOST_FOREACH(const std::string &name, _dboard_manager->get_rx_subdev_names()){
+ dboard_manager::populate_prop_tree_from_subdev(
+ _tree->subtree(mb_path / "dboards/A/rx_frontends" / name),
+ _dboard_manager->get_rx_subdev(name)
+ );
+ }
+ BOOST_FOREACH(const std::string &name, _dboard_manager->get_tx_subdev_names()){
+ dboard_manager::populate_prop_tree_from_subdev(
+ _tree->subtree(mb_path / "dboards/A/tx_frontends" / name),
+ _dboard_manager->get_tx_subdev(name)
+ );
+ }
+
+ //initialize io handling
+ this->io_init();
+
+ ////////////////////////////////////////////////////////////////////
+ // do some post-init tasks
+ ////////////////////////////////////////////////////////////////////
+ _tree->access<double>(mb_path / "tick_rate").update() //update and then subscribe the clock callback
+ .subscribe(boost::bind(&e100_clock_ctrl::set_fpga_clock_rate, _clock_ctrl, _1));
+
+ //and now that the tick rate is set, init the host rates to something
+ BOOST_FOREACH(const std::string &name, _tree->list(mb_path / "rx_dsps")){
+ _tree->access<double>(mb_path / "rx_dsps" / name / "rate" / "value").set(1e6);
+ }
+ BOOST_FOREACH(const std::string &name, _tree->list(mb_path / "tx_dsps")){
+ _tree->access<double>(mb_path / "tx_dsps" / name / "rate" / "value").set(1e6);
+ }
+
+ _tree->access<subdev_spec_t>(mb_path / "rx_subdev_spec").set(subdev_spec_t("A:"+_dboard_manager->get_rx_subdev_names()[0]));
+ _tree->access<subdev_spec_t>(mb_path / "tx_subdev_spec").set(subdev_spec_t("A:"+_dboard_manager->get_tx_subdev_names()[0]));
+ _tree->access<std::string>(mb_path / "clock_source/value").set("internal");
+ _tree->access<std::string>(mb_path / "time_source/value").set("none");
+
+}
+
+e100_impl::~e100_impl(void){
+ /* NOP */
+}
+
+double e100_impl::update_rx_codec_gain(const double gain){
+ //set gain on both I and Q, readback on one
+ //TODO in the future, gains should have individual control
+ _codec_ctrl->set_rx_pga_gain(gain, 'A');
+ _codec_ctrl->set_rx_pga_gain(gain, 'B');
+ return _codec_ctrl->get_rx_pga_gain('A');
+}
+
+void e100_impl::set_mb_eeprom(const uhd::usrp::mboard_eeprom_t &mb_eeprom){
+ mb_eeprom.commit(*_dev_i2c_iface, mboard_eeprom_t::MAP_E100);
+}
+
+void e100_impl::set_db_eeprom(const std::string &type, const uhd::usrp::dboard_eeprom_t &db_eeprom){
+ if (type == "rx") db_eeprom.store(*_fpga_i2c_ctrl, I2C_ADDR_RX_DB);
+ if (type == "tx") db_eeprom.store(*_fpga_i2c_ctrl, I2C_ADDR_TX_DB);
+ if (type == "gdb") db_eeprom.store(*_fpga_i2c_ctrl, I2C_ADDR_TX_DB ^ 5);
+}
+
+void e100_impl::update_clock_source(const std::string &source){
+ if (source == "auto") _clock_ctrl->use_auto_ref();
+ else if (source == "internal") _clock_ctrl->use_internal_ref();
+ else if (source == "external") _clock_ctrl->use_external_ref();
+ else throw uhd::runtime_error("unhandled clock configuration reference source: " + source);
+}
diff --git a/host/lib/usrp/e100/e100_impl.hpp b/host/lib/usrp/e100/e100_impl.hpp
new file mode 100644
index 000000000..e24360223
--- /dev/null
+++ b/host/lib/usrp/e100/e100_impl.hpp
@@ -0,0 +1,129 @@
+//
+// Copyright 2010-2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// 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 "e100_ctrl.hpp"
+#include "clock_ctrl.hpp"
+#include "codec_ctrl.hpp"
+#include "spi_core_100.hpp"
+#include "i2c_core_100.hpp"
+#include "rx_frontend_core_200.hpp"
+#include "tx_frontend_core_200.hpp"
+#include "rx_dsp_core_200.hpp"
+#include "tx_dsp_core_200.hpp"
+#include "time64_core_200.hpp"
+#include <uhd/device.hpp>
+#include <uhd/property_tree.hpp>
+#include <uhd/utils/pimpl.hpp>
+#include <uhd/usrp/subdev_spec.hpp>
+#include <uhd/usrp/dboard_eeprom.hpp>
+#include <uhd/usrp/mboard_eeprom.hpp>
+#include <uhd/types/otw_type.hpp>
+#include <uhd/types/clock_config.hpp>
+#include <uhd/types/stream_cmd.hpp>
+#include <uhd/usrp/dboard_manager.hpp>
+#include <uhd/transport/zero_copy.hpp>
+
+#ifndef INCLUDED_E100_IMPL_HPP
+#define INCLUDED_E100_IMPL_HPP
+
+uhd::transport::zero_copy_if::sptr e100_make_mmap_zero_copy(e100_ctrl::sptr iface);
+
+static const double E100_LINK_RATE_BPS = 256e6/8;
+static const std::string E100_I2C_DEV_NODE = "/dev/i2c-3";
+static const std::string E100_FPGA_FILE_NAME = "usrp_e100_fpga_v2.bin";
+static const boost::uint16_t E100_FPGA_COMPAT_NUM = 0x05;
+static const boost::uint32_t E100_RX_SID_BASE = 2;
+static const boost::uint32_t E100_TX_ASYNC_SID = 1;
+static const double E100_DEFAULT_CLOCK_RATE = 64e6;
+
+//! load an fpga image from a bin file into the usrp-e fpga
+extern void e100_load_fpga(const std::string &bin_file);
+
+//! Make an e100 dboard interface
+uhd::usrp::dboard_iface::sptr make_e100_dboard_iface(
+ wb_iface::sptr wb_iface,
+ uhd::i2c_iface::sptr i2c_iface,
+ uhd::spi_iface::sptr spi_iface,
+ e100_clock_ctrl::sptr clock,
+ e100_codec_ctrl::sptr codec
+);
+
+/*!
+ * USRP-E100 implementation guts:
+ * The implementation details are encapsulated here.
+ * Handles properties on the mboard, dboard, dsps...
+ */
+class e100_impl : public uhd::device{
+public:
+ //structors
+ e100_impl(const uhd::device_addr_t &);
+ ~e100_impl(void);
+
+ //the io interface
+ size_t send(const send_buffs_type &, size_t, const uhd::tx_metadata_t &, const uhd::io_type_t &, send_mode_t, double);
+ size_t recv(const recv_buffs_type &, size_t, uhd::rx_metadata_t &, const uhd::io_type_t &, recv_mode_t, double);
+ bool recv_async_msg(uhd::async_metadata_t &, double);
+ size_t get_max_send_samps_per_packet(void) const;
+ size_t get_max_recv_samps_per_packet(void) const;
+
+private:
+ uhd::property_tree::sptr _tree;
+
+ //controllers
+ spi_core_100::sptr _fpga_spi_ctrl;
+ i2c_core_100::sptr _fpga_i2c_ctrl;
+ rx_frontend_core_200::sptr _rx_fe;
+ tx_frontend_core_200::sptr _tx_fe;
+ std::vector<rx_dsp_core_200::sptr> _rx_dsps;
+ tx_dsp_core_200::sptr _tx_dsp;
+ time64_core_200::sptr _time64;
+ e100_clock_ctrl::sptr _clock_ctrl;
+ e100_codec_ctrl::sptr _codec_ctrl;
+ e100_ctrl::sptr _fpga_ctrl;
+ uhd::i2c_iface::sptr _dev_i2c_iface;
+ uhd::spi_iface::sptr _aux_spi_iface;
+
+ //transports
+ uhd::transport::zero_copy_if::sptr _data_transport;
+
+ //dboard stuff
+ uhd::usrp::dboard_manager::sptr _dboard_manager;
+ uhd::usrp::dboard_iface::sptr _dboard_iface;
+
+ //handle io stuff
+ uhd::otw_type_t _rx_otw_type, _tx_otw_type;
+ UHD_PIMPL_DECL(io_impl) _io_impl;
+ void io_init(void);
+
+ //device properties interface
+ void get(const wax::obj &, wax::obj &val){
+ val = _tree; //entry point into property tree
+ }
+
+ double update_rx_codec_gain(const double); //sets A and B at once
+ void set_mb_eeprom(const uhd::usrp::mboard_eeprom_t &);
+ void set_db_eeprom(const std::string &, const uhd::usrp::dboard_eeprom_t &);
+ void update_tick_rate(const double rate);
+ void update_rx_samp_rate(const double rate);
+ void update_tx_samp_rate(const double rate);
+ void update_rx_subdev_spec(const uhd::usrp::subdev_spec_t &);
+ void update_tx_subdev_spec(const uhd::usrp::subdev_spec_t &);
+ void update_clock_source(const std::string &);
+
+};
+
+#endif /* INCLUDED_E100_IMPL_HPP */
diff --git a/host/lib/usrp/usrp_e100/usrp_e100_mmap_zero_copy.cpp b/host/lib/usrp/e100/e100_mmap_zero_copy.cpp
index bb421507a..cdb7094f4 100644
--- a/host/lib/usrp/usrp_e100/usrp_e100_mmap_zero_copy.cpp
+++ b/host/lib/usrp/e100/e100_mmap_zero_copy.cpp
@@ -15,7 +15,7 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
-#include "usrp_e100_iface.hpp"
+#include "e100_ctrl.hpp"
#include <uhd/transport/zero_copy.hpp>
#include <uhd/utils/log.hpp>
#include <uhd/exception.hpp>
@@ -35,9 +35,9 @@ static const size_t poll_breakout = 10; //how many poll timeouts constitute a fu
* Reusable managed receiver buffer:
* - The buffer knows how to claim and release a frame.
**********************************************************************/
-class usrp_e100_mmap_zero_copy_mrb : public managed_recv_buffer{
+class e100_mmap_zero_copy_mrb : public managed_recv_buffer{
public:
- usrp_e100_mmap_zero_copy_mrb(void *mem, ring_buffer_info *info):
+ e100_mmap_zero_copy_mrb(void *mem, ring_buffer_info *info):
_mem(mem), _info(info) { /* NOP */ }
void release(void){
@@ -66,9 +66,9 @@ private:
* Reusable managed send buffer:
* - The buffer knows how to claim and release a frame.
**********************************************************************/
-class usrp_e100_mmap_zero_copy_msb : public managed_send_buffer{
+class e100_mmap_zero_copy_msb : public managed_send_buffer{
public:
- usrp_e100_mmap_zero_copy_msb(void *mem, ring_buffer_info *info, size_t len, int fd):
+ e100_mmap_zero_copy_msb(void *mem, ring_buffer_info *info, size_t len, int fd):
_mem(mem), _info(info), _len(len), _fd(fd) { /* NOP */ }
void commit(size_t len){
@@ -102,9 +102,9 @@ private:
/***********************************************************************
* The zero copy interface implementation
**********************************************************************/
-class usrp_e100_mmap_zero_copy_impl : public zero_copy_if{
+class e100_mmap_zero_copy_impl : public zero_copy_if{
public:
- usrp_e100_mmap_zero_copy_impl(usrp_e100_iface::sptr iface):
+ e100_mmap_zero_copy_impl(e100_ctrl::sptr iface):
_fd(iface->get_file_descriptor()), _recv_index(0), _send_index(0)
{
//get system sizes
@@ -162,28 +162,28 @@ public:
//initialize the managed receive buffers
for (size_t i = 0; i < get_num_recv_frames(); i++){
- _mrb_pool.push_back(usrp_e100_mmap_zero_copy_mrb(
+ _mrb_pool.push_back(e100_mmap_zero_copy_mrb(
recv_buff + get_recv_frame_size()*i, (*recv_info) + i
));
}
//initialize the managed send buffers
for (size_t i = 0; i < get_num_recv_frames(); i++){
- _msb_pool.push_back(usrp_e100_mmap_zero_copy_msb(
+ _msb_pool.push_back(e100_mmap_zero_copy_msb(
send_buff + get_send_frame_size()*i, (*send_info) + i,
get_send_frame_size(), _fd
));
}
}
- ~usrp_e100_mmap_zero_copy_impl(void){
+ ~e100_mmap_zero_copy_impl(void){
UHD_LOG << "cleanup: munmap" << std::endl;
::munmap(_mapped_mem, _map_size);
}
managed_recv_buffer::sptr get_recv_buff(double timeout){
if (fp_verbose) UHD_LOGV(always) << "get_recv_buff: " << _recv_index << std::endl;
- usrp_e100_mmap_zero_copy_mrb &mrb = _mrb_pool[_recv_index];
+ e100_mmap_zero_copy_mrb &mrb = _mrb_pool[_recv_index];
//poll/wait for a ready frame
if (not mrb.ready()){
@@ -215,7 +215,7 @@ public:
managed_send_buffer::sptr get_send_buff(double timeout){
if (fp_verbose) UHD_LOGV(always) << "get_send_buff: " << _send_index << std::endl;
- usrp_e100_mmap_zero_copy_msb &msb = _msb_pool[_send_index];
+ e100_mmap_zero_copy_msb &msb = _msb_pool[_send_index];
//poll/wait for a ready frame
if (not msb.ready()){
@@ -254,8 +254,8 @@ private:
size_t _frame_size, _map_size;
//re-usable managed buffers
- std::vector<usrp_e100_mmap_zero_copy_mrb> _mrb_pool;
- std::vector<usrp_e100_mmap_zero_copy_msb> _msb_pool;
+ std::vector<e100_mmap_zero_copy_mrb> _mrb_pool;
+ std::vector<e100_mmap_zero_copy_msb> _msb_pool;
//indexes into sub-sections of mapped memory
size_t _recv_index, _send_index;
@@ -264,6 +264,6 @@ private:
/***********************************************************************
* The zero copy interface make function
**********************************************************************/
-zero_copy_if::sptr usrp_e100_make_mmap_zero_copy(usrp_e100_iface::sptr iface){
- return zero_copy_if::sptr(new usrp_e100_mmap_zero_copy_impl(iface));
+zero_copy_if::sptr e100_make_mmap_zero_copy(e100_ctrl::sptr iface){
+ return zero_copy_if::sptr(new e100_mmap_zero_copy_impl(iface));
}
diff --git a/host/lib/usrp/e100/e100_regs.hpp b/host/lib/usrp/e100/e100_regs.hpp
new file mode 100644
index 000000000..28ef707dc
--- /dev/null
+++ b/host/lib/usrp/e100/e100_regs.hpp
@@ -0,0 +1,157 @@
+
+
+////////////////////////////////////////////////////////////////
+//
+// Memory map for embedded wishbone bus
+//
+////////////////////////////////////////////////////////////////
+
+// All addresses are byte addresses. All accesses are word (16-bit) accesses.
+// This means that address bit 0 is usually 0.
+// There are 11 bits of address for the control.
+
+#ifndef INCLUDED_E100_REGS_HPP
+#define INCLUDED_E100_REGS_HPP
+
+/////////////////////////////////////////////////////
+// Slave pointers
+
+#define E100_REG_SLAVE(n) ((n)<<7)
+
+/////////////////////////////////////////////////////
+// Slave 0 -- Misc Regs
+
+#define E100_REG_MISC_BASE E100_REG_SLAVE(0)
+
+#define E100_REG_MISC_LED E100_REG_MISC_BASE + 0
+#define E100_REG_MISC_SW E100_REG_MISC_BASE + 2
+#define E100_REG_MISC_CGEN_CTRL E100_REG_MISC_BASE + 4
+#define E100_REG_MISC_CGEN_ST E100_REG_MISC_BASE + 6
+#define E100_REG_MISC_TEST E100_REG_MISC_BASE + 8
+#define E100_REG_MISC_RX_LEN E100_REG_MISC_BASE + 10
+#define E100_REG_MISC_TX_LEN E100_REG_MISC_BASE + 12
+#define E100_REG_MISC_XFER_RATE E100_REG_MISC_BASE + 14
+#define E100_REG_MISC_COMPAT E100_REG_MISC_BASE + 16
+
+/////////////////////////////////////////////////////
+// Slave 1 -- UART
+// CLKDIV is 16 bits, others are only 8
+
+#define E100_REG_UART_BASE E100_REG_SLAVE(1)
+
+#define E100_REG_UART_CLKDIV E100_REG_UART_BASE + 0
+#define E100_REG_UART_TXLEVEL E100_REG_UART_BASE + 2
+#define E100_REG_UART_RXLEVEL E100_REG_UART_BASE + 4
+#define E100_REG_UART_TXCHAR E100_REG_UART_BASE + 6
+#define E100_REG_UART_RXCHAR E100_REG_UART_BASE + 8
+
+/////////////////////////////////////////////////////
+// Slave 2 -- SPI Core
+//these are 32-bit registers mapped onto the 16-bit Wishbone bus.
+//Using peek32/poke32 should allow transparent use of these registers.
+#define E100_REG_SPI_BASE E100_REG_SLAVE(2)
+
+//spi slave constants
+#define UE_SPI_SS_AD9522 (1 << 3)
+#define UE_SPI_SS_AD9862 (1 << 2)
+#define UE_SPI_SS_TX_DB (1 << 1)
+#define UE_SPI_SS_RX_DB (1 << 0)
+
+////////////////////////////////////////////////
+// Slave 3 -- I2C Core
+
+#define E100_REG_I2C_BASE E100_REG_SLAVE(3)
+
+////////////////////////////////////////////////
+// Slave 5 -- Error messages buffer
+
+#define E100_REG_ERR_BUFF E100_REG_SLAVE(5)
+
+////////////////////////////////////////////////
+// Slave 4 -- GPIO
+
+#define E100_REG_GPIO_BASE E100_REG_SLAVE(4)
+
+#define E100_REG_GPIO_RX_IO E100_REG_GPIO_BASE + 0
+#define E100_REG_GPIO_TX_IO E100_REG_GPIO_BASE + 2
+#define E100_REG_GPIO_RX_DDR E100_REG_GPIO_BASE + 4
+#define E100_REG_GPIO_TX_DDR E100_REG_GPIO_BASE + 6
+#define E100_REG_GPIO_RX_SEL E100_REG_GPIO_BASE + 8
+#define E100_REG_GPIO_TX_SEL E100_REG_GPIO_BASE + 10
+#define E100_REG_GPIO_RX_DBG E100_REG_GPIO_BASE + 12
+#define E100_REG_GPIO_TX_DBG E100_REG_GPIO_BASE + 14
+
+//possible bit values for sel when dbg is 0:
+#define GPIO_SEL_SW 0 // if pin is an output, set by software in the io reg
+#define GPIO_SEL_ATR 1 // if pin is an output, set by ATR logic
+
+//possible bit values for sel when dbg is 1:
+#define GPIO_SEL_DEBUG_0 0 // if pin is an output, debug lines from FPGA fabric
+#define GPIO_SEL_DEBUG_1 1 // if pin is an output, debug lines from FPGA fabric
+
+///////////////////////////////////////////////////
+// Slave 6 -- ATR Controller
+// 16 regs
+
+#define E100_REG_ATR_BASE E100_REG_SLAVE(6)
+
+#define E100_REG_ATR_IDLE_RXSIDE E100_REG_ATR_BASE + 0
+#define E100_REG_ATR_IDLE_TXSIDE E100_REG_ATR_BASE + 2
+#define E100_REG_ATR_INTX_RXSIDE E100_REG_ATR_BASE + 4
+#define E100_REG_ATR_INTX_TXSIDE E100_REG_ATR_BASE + 6
+#define E100_REG_ATR_INRX_RXSIDE E100_REG_ATR_BASE + 8
+#define E100_REG_ATR_INRX_TXSIDE E100_REG_ATR_BASE + 10
+#define E100_REG_ATR_FULL_RXSIDE E100_REG_ATR_BASE + 12
+#define E100_REG_ATR_FULL_TXSIDE E100_REG_ATR_BASE + 14
+
+///////////////////////////////////////////////////
+// Slave 7 -- Readback Mux 32
+
+#define E100_REG_RB_MUX_32_BASE E100_REG_SLAVE(7)
+
+#define E100_REG_RB_TIME_NOW_SECS E100_REG_RB_MUX_32_BASE + 0
+#define E100_REG_RB_TIME_NOW_TICKS E100_REG_RB_MUX_32_BASE + 4
+#define E100_REG_RB_TIME_PPS_SECS E100_REG_RB_MUX_32_BASE + 8
+#define E100_REG_RB_TIME_PPS_TICKS E100_REG_RB_MUX_32_BASE + 12
+#define E100_REG_RB_MISC_TEST32 E100_REG_RB_MUX_32_BASE + 16
+#define E100_REG_RB_ERR_STATUS E100_REG_RB_MUX_32_BASE + 20
+
+////////////////////////////////////////////////////
+// Slave 8 -- Settings Bus
+//
+// Output-only, no readback, 64 registers total
+// Each register must be written 64 bits at a time
+// First the address xxx_xx00 and then xxx_xx10
+
+// 64 total regs in address space
+#define UE_SR_RX_CTRL0 0 // 9 regs (+0 to +8)
+#define UE_SR_RX_DSP0 10 // 4 regs (+0 to +3)
+#define UE_SR_RX_CTRL1 16 // 9 regs (+0 to +8)
+#define UE_SR_RX_DSP1 26 // 4 regs (+0 to +3)
+#define UE_SR_ERR_CTRL 30 // 1 reg
+#define UE_SR_TX_CTRL 32 // 4 regs (+0 to +3)
+#define UE_SR_TX_DSP 38 // 3 regs (+0 to +2)
+
+#define UE_SR_TIME64 42 // 6 regs (+0 to +5)
+#define UE_SR_RX_FRONT 48 // 5 regs (+0 to +4)
+#define UE_SR_TX_FRONT 54 // 5 regs (+0 to +4)
+
+#define UE_SR_REG_TEST32 60 // 1 reg
+#define UE_SR_CLEAR_RX_FIFO 61 // 1 reg
+#define UE_SR_CLEAR_TX_FIFO 62 // 1 reg
+#define UE_SR_GLOBAL_RESET 63 // 1 reg
+
+#define E100_REG_SR_ADDR(n) (E100_REG_SLAVE(8) + (4*(n)))
+
+#define E100_REG_SR_MISC_TEST32 E100_REG_SR_ADDR(UE_SR_REG_TEST32)
+#define E100_REG_SR_ERR_CTRL E100_REG_SR_ADDR(UE_SR_ERR_CTRL)
+
+/////////////////////////////////////////////////
+// Magic reset regs
+////////////////////////////////////////////////
+#define E100_REG_CLEAR_RX E100_REG_SR_ADDR(UE_SR_CLEAR_RX_FIFO)
+#define E100_REG_CLEAR_TX E100_REG_SR_ADDR(UE_SR_CLEAR_RX_FIFO)
+#define E100_REG_GLOBAL_RESET E100_REG_SR_ADDR(UE_SR_GLOBAL_RESET)
+
+#endif
+
diff --git a/host/lib/usrp/usrp_e100/fpga_downloader.cpp b/host/lib/usrp/e100/fpga_downloader.cpp
index a7449d3b1..7074c8299 100644
--- a/host/lib/usrp/usrp_e100/fpga_downloader.cpp
+++ b/host/lib/usrp/e100/fpga_downloader.cpp
@@ -245,7 +245,7 @@ static void send_file_to_fpga(const std::string &file_name, gpio &error, gpio &d
}//namespace usrp_e_fpga_downloader_utility
-void usrp_e100_load_fpga(const std::string &bin_file){
+void e100_load_fpga(const std::string &bin_file){
using namespace usrp_e_fpga_downloader_utility;
gpio gpio_prog_b(PROG_B, OUT);
@@ -254,9 +254,9 @@ void usrp_e100_load_fpga(const std::string &bin_file){
UHD_MSG(status) << "Loading FPGA image: " << bin_file << "... " << std::flush;
- if(std::system("/sbin/rmmod usrp_e") != 0){
- UHD_MSG(warning) << "USRP-E100 FPGA downloader: could not unload usrp_e module" << std::endl;
- }
+// if(std::system("/sbin/rmmod usrp_e") != 0){
+// UHD_MSG(warning) << "USRP-E100 FPGA downloader: could not unload usrp_e module" << std::endl;
+// }
prepare_fpga_for_configuration(gpio_prog_b, gpio_init_b);
@@ -264,9 +264,9 @@ void usrp_e100_load_fpga(const std::string &bin_file){
send_file_to_fpga(bin_file, gpio_init_b, gpio_done);
- if(std::system("/sbin/modprobe usrp_e") != 0){
- UHD_MSG(warning) << "USRP-E100 FPGA downloader: could not load usrp_e module" << std::endl;
- }
+// if(std::system("/sbin/modprobe usrp_e") != 0){
+// UHD_MSG(warning) << "USRP-E100 FPGA downloader: could not load usrp_e module" << std::endl;
+// }
}
diff --git a/host/lib/usrp/usrp_e100/include/linux/usrp_e.h b/host/lib/usrp/e100/include/linux/usrp_e.h
index 4c6a5dd89..2c4aa2ac1 100644
--- a/host/lib/usrp/usrp_e100/include/linux/usrp_e.h
+++ b/host/lib/usrp/e100/include/linux/usrp_e.h
@@ -28,46 +28,15 @@ struct usrp_e_ctl32 {
__u32 buf[10];
};
-/* SPI interface */
-
-#define UE_SPI_TXONLY 0
-#define UE_SPI_TXRX 1
-
-/* Defines for spi ctrl register */
-#define UE_SPI_CTRL_TXNEG (1<<10)
-#define UE_SPI_CTRL_RXNEG (1<<9)
-
-#define UE_SPI_PUSH_RISE 0
-#define UE_SPI_PUSH_FALL UE_SPI_CTRL_TXNEG
-#define UE_SPI_LATCH_RISE 0
-#define UE_SPI_LATCH_FALL UE_SPI_CTRL_RXNEG
-
-struct usrp_e_spi {
- __u8 readback;
- __u32 slave;
- __u32 data;
- __u32 length;
- __u32 flags;
-};
-
-struct usrp_e_i2c {
- __u8 addr;
- __u32 len;
- __u8 data[];
-};
-
#define USRP_E_IOC_MAGIC 'u'
#define USRP_E_WRITE_CTL16 _IOW(USRP_E_IOC_MAGIC, 0x20, struct usrp_e_ctl16)
#define USRP_E_READ_CTL16 _IOWR(USRP_E_IOC_MAGIC, 0x21, struct usrp_e_ctl16)
#define USRP_E_WRITE_CTL32 _IOW(USRP_E_IOC_MAGIC, 0x22, struct usrp_e_ctl32)
#define USRP_E_READ_CTL32 _IOWR(USRP_E_IOC_MAGIC, 0x23, struct usrp_e_ctl32)
-#define USRP_E_SPI _IOWR(USRP_E_IOC_MAGIC, 0x24, struct usrp_e_spi)
-#define USRP_E_I2C_READ _IOWR(USRP_E_IOC_MAGIC, 0x25, struct usrp_e_i2c)
-#define USRP_E_I2C_WRITE _IOW(USRP_E_IOC_MAGIC, 0x26, struct usrp_e_i2c)
#define USRP_E_GET_RB_INFO _IOR(USRP_E_IOC_MAGIC, 0x27, struct usrp_e_ring_buffer_size_t)
#define USRP_E_GET_COMPAT_NUMBER _IO(USRP_E_IOC_MAGIC, 0x28)
-#define USRP_E_COMPAT_NUMBER 1
+#define USRP_E_COMPAT_NUMBER 2
/* Flag defines */
#define RB_USER (1<<0)
diff --git a/host/lib/usrp/e100/io_impl.cpp b/host/lib/usrp/e100/io_impl.cpp
new file mode 100644
index 000000000..a10b3ffb3
--- /dev/null
+++ b/host/lib/usrp/e100/io_impl.cpp
@@ -0,0 +1,327 @@
+//
+// Copyright 2010-2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// 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 "recv_packet_demuxer.hpp"
+#include "validate_subdev_spec.hpp"
+#include "../../transport/super_recv_packet_handler.hpp"
+#include "../../transport/super_send_packet_handler.hpp"
+#include <linux/usrp_e.h> //ioctl structures and constants
+#include "e100_impl.hpp"
+#include "e100_regs.hpp"
+#include <uhd/utils/msg.hpp>
+#include <uhd/utils/log.hpp>
+#include <uhd/utils/tasks.hpp>
+#include <uhd/utils/thread_priority.hpp>
+#include <uhd/transport/bounded_buffer.hpp>
+#include <boost/bind.hpp>
+#include <boost/format.hpp>
+#include <boost/bind.hpp>
+#include <boost/thread/thread.hpp>
+#include <poll.h> //poll
+#include <fcntl.h> //open, close
+#include <sstream>
+#include <fstream>
+
+using namespace uhd;
+using namespace uhd::usrp;
+using namespace uhd::transport;
+
+/***********************************************************************
+ * io impl details (internal to this file)
+ * - pirate crew of 1
+ * - bounded buffer
+ * - thread loop
+ * - vrt packet handler states
+ **********************************************************************/
+struct e100_impl::io_impl{
+ io_impl(void):
+ false_alarm(0), async_msg_fifo(100/*messages deep*/)
+ { /* NOP */ }
+
+ double tick_rate; //set by update tick rate method
+ e100_ctrl::sptr iface; //so handle irq can peek and poke
+ void handle_irq(void);
+ size_t false_alarm;
+ //The data transport is listed first so that it is deconstructed last,
+ //which is after the states and booty which may hold managed buffers.
+ recv_packet_demuxer::sptr demuxer;
+
+ //state management for the vrt packet handler code
+ sph::recv_packet_handler recv_handler;
+ sph::send_packet_handler send_handler;
+
+ //a pirate's life is the life for me!
+ void recv_pirate_loop(
+ spi_iface::sptr //keep a sptr to iface which shares gpio147
+ ){
+ //open the GPIO and set it up for an IRQ
+ std::ofstream edge_file("/sys/class/gpio/gpio147/edge");
+ edge_file << "rising" << std::endl << std::flush;
+ edge_file.close();
+ int fd = ::open("/sys/class/gpio/gpio147/value", O_RDONLY);
+ if (fd < 0) UHD_MSG(error) << "Unable to open GPIO for IRQ\n";
+
+ while (not boost::this_thread::interruption_requested()){
+ pollfd pfd;
+ pfd.fd = fd;
+ pfd.events = POLLPRI | POLLERR;
+ ssize_t ret = ::poll(&pfd, 1, 100/*ms*/);
+ if (ret > 0) this->handle_irq();
+ }
+
+ //cleanup before thread exit
+ ::close(fd);
+ }
+ bounded_buffer<async_metadata_t> async_msg_fifo;
+ task::sptr pirate_task;
+};
+
+void e100_impl::io_impl::handle_irq(void){
+ //check the status of the async msg buffer
+ const boost::uint32_t status = iface->peek32(E100_REG_RB_ERR_STATUS);
+ if ((status & 0x3) == 0){ //not done or error
+ //This could be a false-alarm because spi readback is mixed in.
+ //So we just sleep for a bit rather than interrupt continuously.
+ if (false_alarm++ > 3) boost::this_thread::sleep(boost::posix_time::milliseconds(1));
+ return;
+ }
+ false_alarm = 0; //its a real message, reset the count...
+ //std::cout << boost::format("status: 0x%x") % status << std::endl;
+
+ //load the data struct and call the ioctl
+ usrp_e_ctl32 data;
+ data.offset = E100_REG_ERR_BUFF;
+ data.count = status >> 16;
+ iface->ioctl(USRP_E_READ_CTL32, &data);
+ //for (size_t i = 0; i < data.count; i++){
+ //data.buf[i] = iface->peek32(E100_REG_ERR_BUFF + i*sizeof(boost::uint32_t));
+ //std::cout << boost::format(" buff[%u] = 0x%08x\n") % i % data.buf[i];
+ //}
+
+ //unpack the vrt header and process below...
+ vrt::if_packet_info_t if_packet_info;
+ if_packet_info.num_packet_words32 = data.count;
+ try{vrt::if_hdr_unpack_le(data.buf, if_packet_info);}
+ catch(const std::exception &e){
+ UHD_MSG(error) << "Error unpacking vrt header:\n" << e.what() << std::endl;
+ goto prepare;
+ }
+
+ //handle a tx async report message
+ if (if_packet_info.sid == E100_TX_ASYNC_SID 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 = 0;
+ 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), long(if_packet_info.tsf), tick_rate
+ );
+ metadata.event_code = async_metadata_t::event_code_t(sph::get_context_code(data.buf, if_packet_info));
+
+ //push the message onto the queue
+ async_msg_fifo.push_with_pop_on_full(metadata);
+
+ //print some fastpath messages
+ if (metadata.event_code &
+ ( async_metadata_t::EVENT_CODE_UNDERFLOW
+ | async_metadata_t::EVENT_CODE_UNDERFLOW_IN_PACKET)
+ ) UHD_MSG(fastpath) << "U";
+ else if (metadata.event_code &
+ ( async_metadata_t::EVENT_CODE_SEQ_ERROR
+ | async_metadata_t::EVENT_CODE_SEQ_ERROR_IN_BURST)
+ ) UHD_MSG(fastpath) << "S";
+ }
+
+ //prepare for the next round
+ prepare:
+ iface->poke32(E100_REG_SR_ERR_CTRL, 1 << 0); //clear
+ while ((iface->peek32(E100_REG_RB_ERR_STATUS) & (1 << 2)) == 0){} //wait for idle
+ iface->poke32(E100_REG_SR_ERR_CTRL, 1 << 1); //start
+}
+
+/***********************************************************************
+ * Helper Functions
+ **********************************************************************/
+void e100_impl::io_init(void){
+
+ //setup rx otw type
+ _rx_otw_type.width = 16;
+ _rx_otw_type.shift = 0;
+ _rx_otw_type.byteorder = uhd::otw_type_t::BO_LITTLE_ENDIAN;
+
+ //setup tx otw type
+ _tx_otw_type.width = 16;
+ _tx_otw_type.shift = 0;
+ _tx_otw_type.byteorder = uhd::otw_type_t::BO_LITTLE_ENDIAN;
+
+ //create new io impl
+ _io_impl = UHD_PIMPL_MAKE(io_impl, ());
+ _io_impl->demuxer = recv_packet_demuxer::make(_data_transport, _rx_dsps.size(), E100_RX_SID_BASE);
+ _io_impl->iface = _fpga_ctrl;
+
+ //clear state machines
+ _fpga_ctrl->poke32(E100_REG_CLEAR_RX, 0);
+ _fpga_ctrl->poke32(E100_REG_CLEAR_TX, 0);
+
+ //prepare the async msg buffer for incoming messages
+ _fpga_ctrl->poke32(E100_REG_SR_ERR_CTRL, 1 << 0); //clear
+ while ((_fpga_ctrl->peek32(E100_REG_RB_ERR_STATUS) & (1 << 2)) == 0){} //wait for idle
+ _fpga_ctrl->poke32(E100_REG_SR_ERR_CTRL, 1 << 1); //start
+
+ //spawn a pirate, yarrr!
+ _io_impl->pirate_task = task::make(boost::bind(
+ &e100_impl::io_impl::recv_pirate_loop, _io_impl.get(), _aux_spi_iface
+ ));
+
+ //init some handler stuff
+ _io_impl->recv_handler.set_vrt_unpacker(&vrt::if_hdr_unpack_le);
+ _io_impl->recv_handler.set_converter(_rx_otw_type);
+ _io_impl->send_handler.set_vrt_packer(&vrt::if_hdr_pack_le);
+ _io_impl->send_handler.set_converter(_tx_otw_type);
+ _io_impl->send_handler.set_max_samples_per_packet(get_max_send_samps_per_packet());
+}
+
+void e100_impl::update_tick_rate(const double rate){
+ _io_impl->tick_rate = rate;
+ boost::mutex::scoped_lock recv_lock = _io_impl->recv_handler.get_scoped_lock();
+ _io_impl->recv_handler.set_tick_rate(rate);
+ boost::mutex::scoped_lock send_lock = _io_impl->send_handler.get_scoped_lock();
+ _io_impl->send_handler.set_tick_rate(rate);
+}
+
+void e100_impl::update_rx_samp_rate(const double rate){
+ boost::mutex::scoped_lock recv_lock = _io_impl->recv_handler.get_scoped_lock();
+ _io_impl->recv_handler.set_samp_rate(rate);
+ const double adj = _rx_dsps.front()->get_scaling_adjustment();
+ _io_impl->recv_handler.set_scale_factor(adj/32767.);
+}
+
+void e100_impl::update_tx_samp_rate(const double rate){
+ boost::mutex::scoped_lock send_lock = _io_impl->send_handler.get_scoped_lock();
+ _io_impl->send_handler.set_samp_rate(rate);
+}
+
+void e100_impl::update_rx_subdev_spec(const uhd::usrp::subdev_spec_t &spec){
+ boost::mutex::scoped_lock recv_lock = _io_impl->recv_handler.get_scoped_lock();
+ property_tree::path_type root = "/mboards/0/dboards";
+
+ //sanity checking
+ validate_subdev_spec(_tree, spec, "rx");
+
+ //setup mux for this spec
+ bool fe_swapped = false;
+ for (size_t i = 0; i < spec.size(); i++){
+ const std::string conn = _tree->access<std::string>(root / spec[i].db_name / "rx_frontends" / spec[i].sd_name / "connection").get();
+ if (i == 0 and (conn == "QI" or conn == "Q")) fe_swapped = true;
+ _rx_dsps[i]->set_mux(conn, fe_swapped);
+ }
+ _rx_fe->set_mux(fe_swapped);
+
+ //resize for the new occupancy
+ _io_impl->recv_handler.resize(spec.size());
+
+ //bind new callbacks for the handler
+ for (size_t i = 0; i < _io_impl->recv_handler.size(); i++){
+ _rx_dsps[i]->set_nsamps_per_packet(get_max_recv_samps_per_packet()); //seems to be a good place to set this
+ _io_impl->recv_handler.set_xport_chan_get_buff(i, boost::bind(
+ &recv_packet_demuxer::get_recv_buff, _io_impl->demuxer, i, _1
+ ));
+ _io_impl->recv_handler.set_overflow_handler(i, boost::bind(&rx_dsp_core_200::handle_overflow, _rx_dsps[i]));
+ }
+}
+
+void e100_impl::update_tx_subdev_spec(const uhd::usrp::subdev_spec_t &spec){
+ boost::mutex::scoped_lock send_lock = _io_impl->send_handler.get_scoped_lock();
+ property_tree::path_type root = "/mboards/0/dboards";
+
+ //sanity checking
+ validate_subdev_spec(_tree, spec, "tx");
+
+ //set the mux for this spec
+ const std::string conn = _tree->access<std::string>(root / spec[0].db_name / "tx_frontends" / spec[0].sd_name / "connection").get();
+ _tx_fe->set_mux(conn);
+
+ //resize for the new occupancy
+ _io_impl->send_handler.resize(spec.size());
+
+ //bind new callbacks for the handler
+ for (size_t i = 0; i < _io_impl->send_handler.size(); i++){
+ _io_impl->send_handler.set_xport_chan_get_buff(i, boost::bind(
+ &zero_copy_if::get_send_buff, _data_transport, _1
+ ));
+ }
+}
+
+/***********************************************************************
+ * Data Send
+ **********************************************************************/
+size_t e100_impl::get_max_send_samps_per_packet(void) const{
+ static const size_t hdr_size = 0
+ + vrt::max_if_hdr_words32*sizeof(boost::uint32_t)
+ - sizeof(vrt::if_packet_info_t().cid) //no class id ever used
+ ;
+ size_t bpp = _data_transport->get_send_frame_size() - hdr_size;
+ return bpp/_tx_otw_type.get_sample_size();
+}
+
+size_t e100_impl::send(
+ const send_buffs_type &buffs, size_t nsamps_per_buff,
+ const tx_metadata_t &metadata, const io_type_t &io_type,
+ send_mode_t send_mode, double timeout
+){
+ return _io_impl->send_handler.send(
+ buffs, nsamps_per_buff,
+ metadata, io_type,
+ send_mode, timeout
+ );
+}
+
+/***********************************************************************
+ * Data Recv
+ **********************************************************************/
+size_t e100_impl::get_max_recv_samps_per_packet(void) const{
+ static const size_t hdr_size = 0
+ + vrt::max_if_hdr_words32*sizeof(boost::uint32_t)
+ + sizeof(vrt::if_packet_info_t().tlr) //forced to have trailer
+ - sizeof(vrt::if_packet_info_t().cid) //no class id ever used
+ ;
+ size_t bpp = _data_transport->get_recv_frame_size() - hdr_size;
+ return bpp/_rx_otw_type.get_sample_size();
+}
+
+size_t e100_impl::recv(
+ const recv_buffs_type &buffs, size_t nsamps_per_buff,
+ rx_metadata_t &metadata, const io_type_t &io_type,
+ recv_mode_t recv_mode, double timeout
+){
+ return _io_impl->recv_handler.recv(
+ buffs, nsamps_per_buff,
+ metadata, io_type,
+ recv_mode, timeout
+ );
+}
+
+/***********************************************************************
+ * Async Recv
+ **********************************************************************/
+bool e100_impl::recv_async_msg(
+ async_metadata_t &async_metadata, double timeout
+){
+ boost::this_thread::disable_interruption di; //disable because the wait can throw
+ return _io_impl->async_msg_fifo.pop_with_timed_wait(async_metadata, timeout);
+}
diff --git a/host/lib/usrp/mboard_eeprom.cpp b/host/lib/usrp/mboard_eeprom.cpp
index f65b0aac8..35fba547a 100644
--- a/host/lib/usrp/mboard_eeprom.cpp
+++ b/host/lib/usrp/mboard_eeprom.cpp
@@ -351,7 +351,7 @@ mboard_eeprom_t::mboard_eeprom_t(i2c_iface &iface, map_type map){
}
}
-void mboard_eeprom_t::commit(i2c_iface &iface, map_type map){
+void mboard_eeprom_t::commit(i2c_iface &iface, map_type map) const{
switch(map){
case MAP_N100: store_n100(*this, iface); break;
case MAP_B000: store_b000(*this, iface); break;
diff --git a/host/lib/usrp/misc_utils.cpp b/host/lib/usrp/misc_utils.cpp
deleted file mode 100644
index ddcad41cf..000000000
--- a/host/lib/usrp/misc_utils.cpp
+++ /dev/null
@@ -1,225 +0,0 @@
-//
-// Copyright 2010-2011 Ettus Research LLC
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// 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/misc_utils.hpp>
-#include <uhd/utils/assert_has.hpp>
-#include <uhd/utils/algorithm.hpp>
-#include <uhd/utils/gain_group.hpp>
-#include <uhd/usrp/dboard_eeprom.hpp>
-#include <uhd/usrp/subdev_props.hpp>
-#include <uhd/usrp/mboard_props.hpp>
-#include <uhd/usrp/dboard_props.hpp>
-#include <uhd/usrp/codec_props.hpp>
-#include <boost/bind.hpp>
-#include <boost/foreach.hpp>
-#include <boost/format.hpp>
-
-using namespace uhd;
-using namespace uhd::usrp;
-
-/***********************************************************************
- * 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 double get_codec_gain_i(wax::obj codec, const std::string &name){
- return codec[named_prop_t(CODEC_PROP_GAIN_I, name)].as<double>();
-}
-
-static double get_codec_gain_q(wax::obj codec, const std::string &name){
- return codec[named_prop_t(CODEC_PROP_GAIN_Q, name)].as<double>();
-}
-
-static void set_codec_gain_both(wax::obj codec, const std::string &name, double 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, double gain){
- codec[named_prop_t(CODEC_PROP_GAIN_I, name)] = gain;
-}
-
-static void set_codec_gain_q(wax::obj codec, const std::string &name, double 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 double get_subdev_gain(wax::obj subdev, const std::string &name){
- return subdev[named_prop_t(SUBDEV_PROP_GAIN, name)].as<double>();
-}
-
-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, double gain){
- subdev[named_prop_t(SUBDEV_PROP_GAIN, name)] = gain;
-}
-
-/***********************************************************************
- * gain group factory function for usrp
- **********************************************************************/
-gain_group::sptr usrp::make_gain_group(
- const dboard_id_t &dboard_id,
- wax::obj subdev, wax::obj codec,
- gain_group_policy_t gain_group_policy
-){
- const size_t subdev_gain_priority = 1;
- const size_t codec_gain_priority = (gain_group_policy == GAIN_GROUP_POLICY_RX)?
- (subdev_gain_priority - 1): //RX policy, codec gains fill last (lower priority)
- (subdev_gain_priority + 1); //TX policy, codec gains fill first (higher priority)
- const std::string subdev_prefix = dboard_id.to_cname() + "-";
- const std::string codec_prefix = (gain_group_policy == GAIN_GROUP_POLICY_RX)? "ADC-" : "DAC-";
-
- 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(subdev_prefix+name, 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(codec_prefix+name, fcns, codec_gain_priority);
- }
- return gg;
-}
-
-/***********************************************************************
- * verify subdev specs
- **********************************************************************/
-static void verify_xx_subdev_spec(
- mboard_prop_t dboard_names_prop,
- mboard_prop_t dboard_prop,
- subdev_spec_t &subdev_spec,
- wax::obj mboard,
- std::string xx_type
-){
- try{
- prop_names_t dboard_names = mboard[dboard_names_prop].as<prop_names_t>();
- UHD_ASSERT_THROW(dboard_names.size() > 0); //well i hope there is a dboard
-
- //the subdevice specification is empty: handle automatic
- if (subdev_spec.empty()){
- BOOST_FOREACH(const std::string &db_name, dboard_names){
- wax::obj dboard = mboard[named_prop_t(dboard_prop, db_name)];
-
- //if the dboard slot is populated, take the first subdevice
- if (dboard[DBOARD_PROP_DBOARD_EEPROM].as<dboard_eeprom_t>().id != dboard_id_t::none()){
- std::string sd_name = dboard[DBOARD_PROP_SUBDEV_NAMES].as<prop_names_t>().front();
- subdev_spec.push_back(subdev_spec_pair_t(db_name, sd_name));
- break;
- }
- }
-
- //didnt find any populated dboards: add the first subdevice
- if (subdev_spec.empty()){
- std::string db_name = dboard_names.front();
- wax::obj dboard = mboard[named_prop_t(dboard_prop, db_name)];
- std::string sd_name = dboard[DBOARD_PROP_SUBDEV_NAMES].as<prop_names_t>().front();
- subdev_spec.push_back(subdev_spec_pair_t(db_name, sd_name));
- }
- }
-
- //sanity check that the dboard/subdevice names exist for this mboard
- BOOST_FOREACH(subdev_spec_pair_t &pair, subdev_spec){
- //empty db name means select dboard automatically
- if (pair.db_name.empty()){
- if (dboard_names.size() != 1) throw uhd::value_error(
- "A daughterboard name must be provided for multi-slot motherboards: " + subdev_spec.to_string()
- );
- pair.db_name = dboard_names.front();
- }
- uhd::assert_has(dboard_names, pair.db_name, xx_type + " dboard name");
- wax::obj dboard = mboard[named_prop_t(dboard_prop, pair.db_name)];
- prop_names_t subdev_names = dboard[DBOARD_PROP_SUBDEV_NAMES].as<prop_names_t>();
-
- //empty sd name means select the subdev automatically
- if (pair.sd_name.empty()){
- if (subdev_names.size() != 1) throw uhd::value_error(
- "A subdevice name must be provided for multi-subdev daughterboards: " + subdev_spec.to_string()
- );
- pair.sd_name = subdev_names.front();
- }
- uhd::assert_has(subdev_names, pair.sd_name, xx_type + " subdev name");
- }
- }catch(const std::exception &e){
- throw uhd::value_error(str(boost::format(
- "Validate %s subdev spec failed: %s\n %s"
- ) % xx_type % subdev_spec.to_string() % e.what()));
- }
-
- //now use the subdev spec to enable the subdevices in use and vice-versa
- BOOST_FOREACH(const std::string &db_name, mboard[dboard_names_prop].as<prop_names_t>()){
- wax::obj dboard = mboard[named_prop_t(dboard_prop, db_name)];
- BOOST_FOREACH(const std::string &sd_name, dboard[DBOARD_PROP_SUBDEV_NAMES].as<prop_names_t>()){
- try{
- bool enable = uhd::has(subdev_spec, subdev_spec_pair_t(db_name, sd_name));
- dboard[named_prop_t(DBOARD_PROP_SUBDEV, sd_name)][SUBDEV_PROP_ENABLED] = enable;
- }
- catch(const std::exception &e){
- throw uhd::runtime_error(str(boost::format(
- "Cannot set enabled property on subdevice %s:%s\n %s"
- ) % db_name % sd_name % e.what()));
- }
- }
- }
-}
-
-void usrp::verify_rx_subdev_spec(subdev_spec_t &subdev_spec, wax::obj mboard){
- return verify_xx_subdev_spec(
- MBOARD_PROP_RX_DBOARD_NAMES,
- MBOARD_PROP_RX_DBOARD,
- subdev_spec, mboard, "rx"
- );
-}
-
-void usrp::verify_tx_subdev_spec(subdev_spec_t &subdev_spec, wax::obj mboard){
- return verify_xx_subdev_spec(
- MBOARD_PROP_TX_DBOARD_NAMES,
- MBOARD_PROP_TX_DBOARD,
- subdev_spec, mboard, "tx"
- );
-}
diff --git a/host/lib/usrp/multi_usrp.cpp b/host/lib/usrp/multi_usrp.cpp
index 64f82e559..f9f5e675f 100644
--- a/host/lib/usrp/multi_usrp.cpp
+++ b/host/lib/usrp/multi_usrp.cpp
@@ -15,18 +15,13 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
+#include <uhd/property_tree.hpp>
#include <uhd/usrp/multi_usrp.hpp>
-#include <uhd/usrp/tune_helper.hpp>
#include <uhd/usrp/mboard_iface.hpp>
#include <uhd/utils/msg.hpp>
#include <uhd/exception.hpp>
#include <uhd/utils/msg.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>
-#include <uhd/usrp/dboard_props.hpp>
-#include <uhd/usrp/dsp_props.hpp>
#include <boost/thread.hpp>
#include <boost/foreach.hpp>
#include <boost/format.hpp>
@@ -40,15 +35,7 @@ const std::string multi_usrp::ALL_GAINS = "";
/***********************************************************************
* Helper methods
**********************************************************************/
-static inline uhd::freq_range_t add_dsp_shift(
- const uhd::freq_range_t &range,
- wax::obj dsp
-){
- double codec_rate = dsp[uhd::usrp::DSP_PROP_CODEC_RATE].as<double>();
- return uhd::freq_range_t(range.start() - codec_rate/2.0, range.stop() + codec_rate/2.0);
-}
-
-static inline void do_samp_rate_warning_message(
+static void do_samp_rate_warning_message(
double target_rate,
double actual_rate,
const std::string &xx
@@ -63,7 +50,7 @@ static inline void do_samp_rate_warning_message(
}
}
-static inline void do_tune_freq_warning_message(
+static void do_tune_freq_warning_message(
double target_freq,
double actual_freq,
const std::string &xx
@@ -79,12 +66,128 @@ static inline void do_tune_freq_warning_message(
}
/***********************************************************************
+ * Gain helper functions
+ **********************************************************************/
+static double get_gain_value(property_tree::sptr subtree){
+ return subtree->access<double>("value").get();
+}
+
+static void set_gain_value(property_tree::sptr subtree, const double gain){
+ subtree->access<double>("value").set(gain);
+}
+
+static meta_range_t get_gain_range(property_tree::sptr subtree){
+ return subtree->access<meta_range_t>("range").get();
+}
+
+static gain_fcns_t make_gain_fcns_from_subtree(property_tree::sptr subtree){
+ gain_fcns_t gain_fcns;
+ gain_fcns.get_range = boost::bind(&get_gain_range, subtree);
+ gain_fcns.get_value = boost::bind(&get_gain_value, subtree);
+ gain_fcns.set_value = boost::bind(&set_gain_value, subtree, _1);
+ return gain_fcns;
+}
+
+/***********************************************************************
+ * Tune Helper Functions
+ **********************************************************************/
+static const double RX_SIGN = +1.0;
+static const double TX_SIGN = -1.0;
+
+static tune_result_t tune_xx_subdev_and_dsp(
+ const double xx_sign,
+ property_tree::sptr dsp_subtree,
+ property_tree::sptr rf_fe_subtree,
+ const tune_request_t &tune_request
+){
+ //------------------------------------------------------------------
+ //-- calculate the LO offset, only used with automatic policy
+ //------------------------------------------------------------------
+ double lo_offset = 0.0;
+ if (rf_fe_subtree->access<bool>("use_lo_offset").get()){
+ //If the local oscillator will be in the passband, use an offset.
+ //But constrain the LO offset by the width of the filter bandwidth.
+ const double rate = dsp_subtree->access<double>("rate/value").get();
+ const double bw = rf_fe_subtree->access<double>("bandwidth/value").get();
+ if (bw > rate) lo_offset = std::min((bw - rate)/2, rate/2);
+ }
+
+ //------------------------------------------------------------------
+ //-- set the RF frequency depending upon the policy
+ //------------------------------------------------------------------
+ double target_rf_freq = 0.0;
+ switch (tune_request.rf_freq_policy){
+ case tune_request_t::POLICY_AUTO:
+ target_rf_freq = tune_request.target_freq + lo_offset;
+ rf_fe_subtree->access<double>("freq/value").set(target_rf_freq);
+ break;
+
+ case tune_request_t::POLICY_MANUAL:
+ target_rf_freq = tune_request.rf_freq;
+ rf_fe_subtree->access<double>("freq/value").set(target_rf_freq);
+ break;
+
+ case tune_request_t::POLICY_NONE: break; //does not set
+ }
+ const double actual_rf_freq = rf_fe_subtree->access<double>("freq/value").get();
+
+ //------------------------------------------------------------------
+ //-- calculate the dsp freq, only used with automatic policy
+ //------------------------------------------------------------------
+ double target_dsp_freq = actual_rf_freq - tune_request.target_freq;
+
+ //invert the sign on the dsp freq for transmit
+ target_dsp_freq *= xx_sign;
+
+ //------------------------------------------------------------------
+ //-- set the dsp frequency depending upon the dsp frequency policy
+ //------------------------------------------------------------------
+ switch (tune_request.dsp_freq_policy){
+ case tune_request_t::POLICY_AUTO:
+ dsp_subtree->access<double>("freq/value").set(target_dsp_freq);
+ break;
+
+ case tune_request_t::POLICY_MANUAL:
+ target_dsp_freq = tune_request.dsp_freq;
+ dsp_subtree->access<double>("freq/value").set(target_dsp_freq);
+ break;
+
+ case tune_request_t::POLICY_NONE: break; //does not set
+ }
+ const double actual_dsp_freq = dsp_subtree->access<double>("freq/value").get();
+
+ //------------------------------------------------------------------
+ //-- load and return the tune result
+ //------------------------------------------------------------------
+ tune_result_t tune_result;
+ tune_result.target_rf_freq = target_rf_freq;
+ tune_result.actual_rf_freq = actual_rf_freq;
+ tune_result.target_dsp_freq = target_dsp_freq;
+ tune_result.actual_dsp_freq = actual_dsp_freq;
+ return tune_result;
+}
+
+static double derive_freq_from_xx_subdev_and_dsp(
+ const double xx_sign,
+ property_tree::sptr dsp_subtree,
+ property_tree::sptr rf_fe_subtree
+){
+ //extract actual dsp and IF frequencies
+ const double actual_rf_freq = rf_fe_subtree->access<double>("freq/value").get();
+ const double actual_dsp_freq = dsp_subtree->access<double>("freq/value").get();
+
+ //invert the sign on the dsp freq for transmit
+ return actual_rf_freq - actual_dsp_freq * xx_sign;
+}
+
+/***********************************************************************
* Multi USRP Implementation
**********************************************************************/
class multi_usrp_impl : public multi_usrp{
public:
multi_usrp_impl(const device_addr_t &addr){
_dev = device::make(addr);
+ _tree = (*_dev)[0].as<property_tree::sptr>();
}
device::sptr get_device(void){
@@ -96,7 +199,7 @@ public:
******************************************************************/
void set_master_clock_rate(double rate, size_t mboard){
if (mboard != ALL_MBOARDS){
- _mboard(mboard)[MBOARD_PROP_CLOCK_RATE] = rate;
+ _tree->access<double>(mb_root(mboard) / "tick_rate").set(rate);
return;
}
for (size_t m = 0; m < get_num_mboards(); m++){
@@ -105,7 +208,7 @@ public:
}
double get_master_clock_rate(size_t mboard){
- return _mboard(mboard)[MBOARD_PROP_CLOCK_RATE].as<double>();
+ return _tree->access<double>(mb_root(mboard) / "tick_rate").get();
}
std::string get_pp_string(void){
@@ -114,13 +217,13 @@ public:
" Device: %s\n"
)
% ((get_num_mboards() > 1)? "Multi" : "Single")
- % (*_dev)[DEVICE_PROP_NAME].as<std::string>()
+ % (_tree->access<std::string>("/name").get())
);
for (size_t m = 0; m < get_num_mboards(); m++){
buff += str(boost::format(
" Mboard %d: %s\n"
) % m
- % _mboard(m)[MBOARD_PROP_NAME].as<std::string>()
+ % (_tree->access<std::string>(mb_root(m) / "name").get())
);
}
@@ -133,9 +236,9 @@ public:
" RX Dboard: %s\n"
" RX Subdev: %s\n"
) % chan
- % _rx_dsp(chan)[DSP_PROP_NAME].as<std::string>()
- % _rx_dboard(chan)[DBOARD_PROP_NAME].as<std::string>()
- % _rx_subdev(chan)[SUBDEV_PROP_NAME].as<std::string>()
+ % rx_dsp_root(chan).leaf()
+ % rx_rf_fe_root(chan).branch_path().branch_path().leaf()
+ % (_tree->access<std::string>(rx_rf_fe_root(chan) / "name").get())
);
}
}
@@ -149,9 +252,9 @@ public:
" TX Dboard: %s\n"
" TX Subdev: %s\n"
) % chan
- % _tx_dsp(chan)[DSP_PROP_NAME].as<std::string>()
- % _tx_dboard(chan)[DBOARD_PROP_NAME].as<std::string>()
- % _tx_subdev(chan)[SUBDEV_PROP_NAME].as<std::string>()
+ % tx_dsp_root(chan).leaf()
+ % tx_rf_fe_root(chan).branch_path().branch_path().leaf()
+ % (_tree->access<std::string>(tx_rf_fe_root(chan) / "name").get())
);
}
}
@@ -160,20 +263,20 @@ public:
}
std::string get_mboard_name(size_t mboard){
- return _mboard(mboard)[MBOARD_PROP_NAME].as<std::string>();
+ return _tree->access<std::string>(mb_root(mboard) / "name").get();
}
time_spec_t get_time_now(size_t mboard = 0){
- return _mboard(mboard)[MBOARD_PROP_TIME_NOW].as<time_spec_t>();
+ return _tree->access<time_spec_t>(mb_root(mboard) / "time/now").get();
}
time_spec_t get_time_last_pps(size_t mboard = 0){
- return _mboard(mboard)[MBOARD_PROP_TIME_PPS].as<time_spec_t>();
+ return _tree->access<time_spec_t>(mb_root(mboard) / "time/pps").get();
}
void set_time_now(const time_spec_t &time_spec, size_t mboard){
if (mboard != ALL_MBOARDS){
- _mboard(mboard)[MBOARD_PROP_TIME_NOW] = time_spec;
+ _tree->access<time_spec_t>(mb_root(mboard) / "time/now").set(time_spec);
return;
}
for (size_t m = 0; m < get_num_mboards(); m++){
@@ -183,7 +286,7 @@ public:
void set_time_next_pps(const time_spec_t &time_spec){
for (size_t m = 0; m < get_num_mboards(); m++){
- _mboard(m)[MBOARD_PROP_TIME_PPS] = time_spec;
+ _tree->access<time_spec_t>(mb_root(m) / "time/pps").set(time_spec);
}
}
@@ -208,8 +311,8 @@ public:
//verify that the time registers are read to be within a few RTT
for (size_t m = 1; m < get_num_mboards(); m++){
- time_spec_t time_0 = _mboard(0)[MBOARD_PROP_TIME_NOW].as<time_spec_t>();
- time_spec_t time_i = _mboard(m)[MBOARD_PROP_TIME_NOW].as<time_spec_t>();
+ time_spec_t time_0 = this->get_time_now(0);
+ time_spec_t time_i = this->get_time_now(m);
if (time_i < time_0 or (time_i - time_0) > time_spec_t(0.01)){ //10 ms: greater than RTT but not too big
UHD_MSG(warning) << boost::format(
"Detected time deviation between board %d and board 0.\n"
@@ -222,8 +325,8 @@ public:
bool get_time_synchronized(void){
for (size_t m = 1; m < get_num_mboards(); m++){
- time_spec_t time_0 = _mboard(0)[MBOARD_PROP_TIME_NOW].as<time_spec_t>();
- time_spec_t time_i = _mboard(m)[MBOARD_PROP_TIME_NOW].as<time_spec_t>();
+ time_spec_t time_0 = this->get_time_now(0);
+ time_spec_t time_i = this->get_time_now(m);
if (time_i < time_0 or (time_i - time_0) > time_spec_t(0.01)) return false;
}
return true;
@@ -231,7 +334,7 @@ public:
void issue_stream_cmd(const stream_cmd_t &stream_cmd, size_t chan){
if (chan != ALL_CHANS){
- _rx_dsp(chan)[DSP_PROP_STREAM_CMD] = stream_cmd;
+ _tree->access<stream_cmd_t>(rx_dsp_root(chan) / "stream_cmd").set(stream_cmd);
return;
}
for (size_t c = 0; c < get_rx_num_channels(); c++){
@@ -241,7 +344,26 @@ public:
void set_clock_config(const clock_config_t &clock_config, size_t mboard){
if (mboard != ALL_MBOARDS){
- _mboard(mboard)[MBOARD_PROP_CLOCK_CONFIG] = clock_config;
+ //set the reference source...
+ std::string clock_source;
+ switch(clock_config.ref_source){
+ case clock_config_t::REF_INT: clock_source = "internal"; break;
+ case clock_config_t::PPS_SMA: clock_source = "external"; break;
+ case clock_config_t::PPS_MIMO: clock_source = "mimo"; break;
+ default: clock_source = "unknown";
+ }
+ if (clock_source == "external" and clock_config.pps_polarity == clock_config_t::PPS_NEG) clock_source = "_external_";
+ _tree->access<std::string>(mb_root(mboard) / "clock_source" / "value").set(clock_source);
+
+ //set the time source
+ std::string time_source;
+ switch(clock_config.pps_source){
+ case clock_config_t::PPS_INT: time_source = "internal"; break;
+ case clock_config_t::PPS_SMA: time_source = "external"; break;
+ case clock_config_t::PPS_MIMO: time_source = "mimo"; break;
+ default: time_source = "unknown";
+ }
+ _tree->access<std::string>(mb_root(mboard) / "time_source" / "value").set(time_source);
return;
}
for (size_t m = 0; m < get_num_mboards(); m++){
@@ -250,19 +372,19 @@ public:
}
size_t get_num_mboards(void){
- return (*_dev)[DEVICE_PROP_MBOARD_NAMES].as<prop_names_t>().size();
+ return _tree->list("/mboards").size();
}
sensor_value_t get_mboard_sensor(const std::string &name, size_t mboard){
- return _mboard(mboard)[named_prop_t(MBOARD_PROP_SENSOR, name)].as<sensor_value_t>();
+ return _tree->access<sensor_value_t>(mb_root(mboard) / "sensors" / name).get();
}
std::vector<std::string> get_mboard_sensor_names(size_t mboard){
- return _mboard(mboard)[MBOARD_PROP_SENSOR_NAMES].as<prop_names_t>();
+ return _tree->list(mb_root(mboard) / "sensors");
}
-
- mboard_iface::sptr get_mboard_iface(size_t mboard){
- return _mboard(mboard)[MBOARD_PROP_IFACE].as<mboard_iface::sptr>();
+
+ mboard_iface::sptr get_mboard_iface(size_t){
+ return mboard_iface::sptr(); //not implemented
}
/*******************************************************************
@@ -270,7 +392,7 @@ public:
******************************************************************/
void set_rx_subdev_spec(const subdev_spec_t &spec, size_t mboard){
if (mboard != ALL_MBOARDS){
- _mboard(mboard)[MBOARD_PROP_RX_SUBDEV_SPEC] = spec;
+ _tree->access<subdev_spec_t>(mb_root(mboard) / "rx_subdev_spec").set(spec);
return;
}
for (size_t m = 0; m < get_num_mboards(); m++){
@@ -279,7 +401,7 @@ public:
}
subdev_spec_t get_rx_subdev_spec(size_t mboard){
- return _mboard(mboard)[MBOARD_PROP_RX_SUBDEV_SPEC].as<subdev_spec_t>();
+ return _tree->access<subdev_spec_t>(mb_root(mboard) / "rx_subdev_spec").get();
}
size_t get_rx_num_channels(void){
@@ -291,12 +413,12 @@ public:
}
std::string get_rx_subdev_name(size_t chan){
- return _rx_subdev(chan)[SUBDEV_PROP_NAME].as<std::string>();
+ return _tree->access<std::string>(rx_rf_fe_root(chan) / "name").get();
}
void set_rx_rate(double rate, size_t chan){
if (chan != ALL_CHANS){
- _rx_dsp(chan)[DSP_PROP_HOST_RATE] = rate;
+ _tree->access<double>(rx_dsp_root(chan) / "rate" / "value").set(rate);
do_samp_rate_warning_message(rate, get_rx_rate(chan), "RX");
return;
}
@@ -306,69 +428,71 @@ public:
}
double get_rx_rate(size_t chan){
- return _rx_dsp(chan)[DSP_PROP_HOST_RATE].as<double>();
+ return _tree->access<double>(rx_dsp_root(chan) / "rate" / "value").get();
}
tune_result_t set_rx_freq(const tune_request_t &tune_request, size_t chan){
- tune_result_t r = tune_rx_subdev_and_dsp(_rx_subdev(chan), _rx_dsp(chan), tune_request);
+ tune_result_t r = tune_xx_subdev_and_dsp(RX_SIGN, _tree->subtree(rx_dsp_root(chan)), _tree->subtree(rx_rf_fe_root(chan)), tune_request);
do_tune_freq_warning_message(tune_request.target_freq, get_rx_freq(chan), "RX");
return r;
}
double get_rx_freq(size_t chan){
- return derive_freq_from_rx_subdev_and_dsp(_rx_subdev(chan), _rx_dsp(chan));
+ return derive_freq_from_xx_subdev_and_dsp(RX_SIGN, _tree->subtree(rx_dsp_root(chan)), _tree->subtree(rx_rf_fe_root(chan)));
}
freq_range_t get_rx_freq_range(size_t chan){
- return add_dsp_shift(_rx_subdev(chan)[SUBDEV_PROP_FREQ_RANGE].as<freq_range_t>(), _rx_dsp(chan));
+ meta_range_t range = _tree->access<meta_range_t>(rx_rf_fe_root(chan) / "freq" / "range").get();
+ meta_range_t dsp_range = _tree->access<meta_range_t>(rx_dsp_root(chan) / "freq" / "range").get();
+ return meta_range_t(range.start() + dsp_range.start(), range.stop() + dsp_range.stop(), dsp_range.step());
}
void set_rx_gain(double gain, const std::string &name, size_t chan){
- return _rx_gain_group(chan)->set_value(gain, name);
+ return rx_gain_group(chan)->set_value(gain, name);
}
double get_rx_gain(const std::string &name, size_t chan){
- return _rx_gain_group(chan)->get_value(name);
+ return rx_gain_group(chan)->get_value(name);
}
gain_range_t get_rx_gain_range(const std::string &name, size_t chan){
- return _rx_gain_group(chan)->get_range(name);
+ return rx_gain_group(chan)->get_range(name);
}
std::vector<std::string> get_rx_gain_names(size_t chan){
- return _rx_gain_group(chan)->get_names();
+ return rx_gain_group(chan)->get_names();
}
void set_rx_antenna(const std::string &ant, size_t chan){
- _rx_subdev(chan)[SUBDEV_PROP_ANTENNA] = ant;
+ _tree->access<std::string>(rx_rf_fe_root(chan) / "antenna" / "value").set(ant);
}
std::string get_rx_antenna(size_t chan){
- return _rx_subdev(chan)[SUBDEV_PROP_ANTENNA].as<std::string>();
+ return _tree->access<std::string>(rx_rf_fe_root(chan) / "antenna" / "value").get();
}
std::vector<std::string> get_rx_antennas(size_t chan){
- return _rx_subdev(chan)[SUBDEV_PROP_ANTENNA_NAMES].as<prop_names_t>();
+ return _tree->access<std::vector<std::string> >(rx_rf_fe_root(chan) / "antenna" / "options").get();
}
void set_rx_bandwidth(double bandwidth, size_t chan){
- _rx_subdev(chan)[SUBDEV_PROP_BANDWIDTH] = bandwidth;
+ _tree->access<double>(rx_rf_fe_root(chan) / "bandwidth" / "value").set(bandwidth);
}
double get_rx_bandwidth(size_t chan){
- return _rx_subdev(chan)[SUBDEV_PROP_BANDWIDTH].as<double>();
+ return _tree->access<double>(rx_rf_fe_root(chan) / "bandwidth" / "value").get();
}
dboard_iface::sptr get_rx_dboard_iface(size_t chan){
- return _rx_dboard(chan)[DBOARD_PROP_DBOARD_IFACE].as<dboard_iface::sptr>();
+ return _tree->access<dboard_iface::sptr>(rx_rf_fe_root(chan).branch_path().branch_path() / "iface").get();
}
sensor_value_t get_rx_sensor(const std::string &name, size_t chan){
- return _rx_subdev(chan)[named_prop_t(SUBDEV_PROP_SENSOR, name)].as<sensor_value_t>();
+ return _tree->access<sensor_value_t>(rx_rf_fe_root(chan) / "sensors" / name).get();
}
std::vector<std::string> get_rx_sensor_names(size_t chan){
- return _rx_subdev(chan)[SUBDEV_PROP_SENSOR_NAMES].as<prop_names_t>();
+ return _tree->list(rx_rf_fe_root(chan) / "sensors");
}
/*******************************************************************
@@ -376,7 +500,7 @@ public:
******************************************************************/
void set_tx_subdev_spec(const subdev_spec_t &spec, size_t mboard){
if (mboard != ALL_MBOARDS){
- _mboard(mboard)[MBOARD_PROP_TX_SUBDEV_SPEC] = spec;
+ _tree->access<subdev_spec_t>(mb_root(mboard) / "tx_subdev_spec").set(spec);
return;
}
for (size_t m = 0; m < get_num_mboards(); m++){
@@ -385,11 +509,11 @@ public:
}
subdev_spec_t get_tx_subdev_spec(size_t mboard){
- return _mboard(mboard)[MBOARD_PROP_TX_SUBDEV_SPEC].as<subdev_spec_t>();
+ return _tree->access<subdev_spec_t>(mb_root(mboard) / "tx_subdev_spec").get();
}
std::string get_tx_subdev_name(size_t chan){
- return _tx_subdev(chan)[SUBDEV_PROP_NAME].as<std::string>();
+ return _tree->access<std::string>(tx_rf_fe_root(chan) / "name").get();
}
size_t get_tx_num_channels(void){
@@ -402,7 +526,7 @@ public:
void set_tx_rate(double rate, size_t chan){
if (chan != ALL_CHANS){
- _tx_dsp(chan)[DSP_PROP_HOST_RATE] = rate;
+ _tree->access<double>(tx_dsp_root(chan) / "rate" / "value").set(rate);
do_samp_rate_warning_message(rate, get_tx_rate(chan), "TX");
return;
}
@@ -412,73 +536,76 @@ public:
}
double get_tx_rate(size_t chan){
- return _tx_dsp(chan)[DSP_PROP_HOST_RATE].as<double>();
+ return _tree->access<double>(tx_dsp_root(chan) / "rate" / "value").get();
}
tune_result_t set_tx_freq(const tune_request_t &tune_request, size_t chan){
- tune_result_t r = tune_tx_subdev_and_dsp(_tx_subdev(chan), _tx_dsp(chan), tune_request);
+ tune_result_t r = tune_xx_subdev_and_dsp(TX_SIGN, _tree->subtree(tx_dsp_root(chan)), _tree->subtree(tx_rf_fe_root(chan)), tune_request);
do_tune_freq_warning_message(tune_request.target_freq, get_tx_freq(chan), "TX");
return r;
}
double get_tx_freq(size_t chan){
- return derive_freq_from_tx_subdev_and_dsp(_tx_subdev(chan), _tx_dsp(chan));
+ return derive_freq_from_xx_subdev_and_dsp(TX_SIGN, _tree->subtree(tx_dsp_root(chan)), _tree->subtree(tx_rf_fe_root(chan)));
}
freq_range_t get_tx_freq_range(size_t chan){
- return add_dsp_shift(_tx_subdev(chan)[SUBDEV_PROP_FREQ_RANGE].as<freq_range_t>(), _tx_dsp(chan));
+ meta_range_t range = _tree->access<meta_range_t>(tx_rf_fe_root(chan) / "freq" / "range").get();
+ meta_range_t dsp_range = _tree->access<meta_range_t>(tx_dsp_root(chan) / "freq" / "range").get();
+ return meta_range_t(range.start() + dsp_range.start(), range.stop() + dsp_range.stop(), dsp_range.step());
}
void set_tx_gain(double gain, const std::string &name, size_t chan){
- return _tx_gain_group(chan)->set_value(gain, name);
+ return tx_gain_group(chan)->set_value(gain, name);
}
double get_tx_gain(const std::string &name, size_t chan){
- return _tx_gain_group(chan)->get_value(name);
+ return tx_gain_group(chan)->get_value(name);
}
gain_range_t get_tx_gain_range(const std::string &name, size_t chan){
- return _tx_gain_group(chan)->get_range(name);
+ return tx_gain_group(chan)->get_range(name);
}
std::vector<std::string> get_tx_gain_names(size_t chan){
- return _tx_gain_group(chan)->get_names();
+ return tx_gain_group(chan)->get_names();
}
void set_tx_antenna(const std::string &ant, size_t chan){
- _tx_subdev(chan)[SUBDEV_PROP_ANTENNA] = ant;
+ _tree->access<std::string>(tx_rf_fe_root(chan) / "antenna" / "value").set(ant);
}
std::string get_tx_antenna(size_t chan){
- return _tx_subdev(chan)[SUBDEV_PROP_ANTENNA].as<std::string>();
+ return _tree->access<std::string>(tx_rf_fe_root(chan) / "antenna" / "value").get();
}
std::vector<std::string> get_tx_antennas(size_t chan){
- return _tx_subdev(chan)[SUBDEV_PROP_ANTENNA_NAMES].as<prop_names_t>();
+ return _tree->access<std::vector<std::string> >(tx_rf_fe_root(chan) / "antenna" / "options").get();
}
void set_tx_bandwidth(double bandwidth, size_t chan){
- _tx_subdev(chan)[SUBDEV_PROP_BANDWIDTH] = bandwidth;
+ _tree->access<double>(tx_rf_fe_root(chan) / "bandwidth" / "value").set(bandwidth);
}
double get_tx_bandwidth(size_t chan){
- return _tx_subdev(chan)[SUBDEV_PROP_BANDWIDTH].as<double>();
+ return _tree->access<double>(tx_rf_fe_root(chan) / "bandwidth" / "value").get();
}
dboard_iface::sptr get_tx_dboard_iface(size_t chan){
- return _tx_dboard(chan)[DBOARD_PROP_DBOARD_IFACE].as<dboard_iface::sptr>();
+ return _tree->access<dboard_iface::sptr>(tx_rf_fe_root(chan).branch_path().branch_path() / "iface").get();
}
sensor_value_t get_tx_sensor(const std::string &name, size_t chan){
- return _tx_subdev(chan)[named_prop_t(SUBDEV_PROP_SENSOR, name)].as<sensor_value_t>();
+ return _tree->access<sensor_value_t>(tx_rf_fe_root(chan) / "sensors" / name).get();
}
std::vector<std::string> get_tx_sensor_names(size_t chan){
- return _tx_subdev(chan)[SUBDEV_PROP_SENSOR_NAMES].as<prop_names_t>();
+ return _tree->list(tx_rf_fe_root(chan) / "sensors");
}
private:
device::sptr _dev;
+ property_tree::sptr _tree;
struct mboard_chan_pair{
size_t mboard, chan;
@@ -507,49 +634,59 @@ private:
return mcp;
}
- wax::obj _mboard(size_t mboard){
- std::string mb_name = (*_dev)[DEVICE_PROP_MBOARD_NAMES].as<prop_names_t>().at(mboard);
- return (*_dev)[named_prop_t(DEVICE_PROP_MBOARD, mb_name)];
+ property_tree::path_type mb_root(const size_t mboard){
+ const std::string name = _tree->list("/mboards").at(mboard);
+ return "/mboards/" + name;
}
- wax::obj _rx_dsp(size_t chan){
- mboard_chan_pair mcp = rx_chan_to_mcp(chan);
- prop_names_t dsp_names = _mboard(mcp.mboard)[MBOARD_PROP_RX_DSP_NAMES].as<prop_names_t>();
- return _mboard(mcp.mboard)[named_prop_t(MBOARD_PROP_RX_DSP, dsp_names.at(mcp.chan))];
- }
- wax::obj _tx_dsp(size_t chan){
- mboard_chan_pair mcp = tx_chan_to_mcp(chan);
- prop_names_t dsp_names = _mboard(mcp.mboard)[MBOARD_PROP_TX_DSP_NAMES].as<prop_names_t>();
- return _mboard(mcp.mboard)[named_prop_t(MBOARD_PROP_TX_DSP, dsp_names.at(mcp.chan))];
- }
- wax::obj _rx_dboard(size_t chan){
+
+ property_tree::path_type rx_dsp_root(const size_t chan){
mboard_chan_pair mcp = rx_chan_to_mcp(chan);
- std::string db_name = get_rx_subdev_spec(mcp.mboard).at(mcp.chan).db_name;
- return _mboard(mcp.mboard)[named_prop_t(MBOARD_PROP_RX_DBOARD, db_name)];
+ const std::string name = _tree->list(mb_root(mcp.mboard) / "rx_dsps").at(mcp.chan);
+ return mb_root(mcp.mboard) / "rx_dsps" / name;
}
- wax::obj _tx_dboard(size_t chan){
+
+ property_tree::path_type tx_dsp_root(const size_t chan){
mboard_chan_pair mcp = tx_chan_to_mcp(chan);
- std::string db_name = get_tx_subdev_spec(mcp.mboard).at(mcp.chan).db_name;
- return _mboard(mcp.mboard)[named_prop_t(MBOARD_PROP_TX_DBOARD, db_name)];
+ const std::string name = _tree->list(mb_root(mcp.mboard) / "tx_dsps").at(mcp.chan);
+ return mb_root(mcp.mboard) / "tx_dsps" / name;
}
- wax::obj _rx_subdev(size_t chan){
+
+ property_tree::path_type rx_rf_fe_root(const size_t chan){
mboard_chan_pair mcp = rx_chan_to_mcp(chan);
- std::string sd_name = get_rx_subdev_spec(mcp.mboard).at(mcp.chan).sd_name;
- return _rx_dboard(chan)[named_prop_t(DBOARD_PROP_SUBDEV, sd_name)];
+ const subdev_spec_pair_t spec = get_rx_subdev_spec(mcp.mboard).at(mcp.chan);
+ return mb_root(mcp.mboard) / "dboards" / spec.db_name / "rx_frontends" / spec.sd_name;
}
- wax::obj _tx_subdev(size_t chan){
+
+ property_tree::path_type tx_rf_fe_root(const size_t chan){
mboard_chan_pair mcp = tx_chan_to_mcp(chan);
- std::string sd_name = get_tx_subdev_spec(mcp.mboard).at(mcp.chan).sd_name;
- return _tx_dboard(chan)[named_prop_t(DBOARD_PROP_SUBDEV, sd_name)];
+ const subdev_spec_pair_t spec = get_tx_subdev_spec(mcp.mboard).at(mcp.chan);
+ return mb_root(mcp.mboard) / "dboards" / spec.db_name / "tx_frontends" / spec.sd_name;
}
- gain_group::sptr _rx_gain_group(size_t chan){
+
+ gain_group::sptr rx_gain_group(size_t chan){
mboard_chan_pair mcp = rx_chan_to_mcp(chan);
- std::string sd_name = get_rx_subdev_spec(mcp.mboard).at(mcp.chan).sd_name;
- return _rx_dboard(chan)[named_prop_t(DBOARD_PROP_GAIN_GROUP, sd_name)].as<gain_group::sptr>();
+ const subdev_spec_pair_t spec = get_rx_subdev_spec(mcp.mboard).at(mcp.chan);
+ gain_group::sptr gg = gain_group::make();
+ BOOST_FOREACH(const std::string &name, _tree->list(mb_root(mcp.mboard) / "rx_codecs" / spec.db_name / "gains")){
+ gg->register_fcns("ADC-"+name, make_gain_fcns_from_subtree(_tree->subtree(mb_root(mcp.mboard) / "rx_codecs" / spec.db_name / "gains" / name)), 0 /* low prio */);
+ }
+ BOOST_FOREACH(const std::string &name, _tree->list(rx_rf_fe_root(chan) / "gains")){
+ gg->register_fcns(name, make_gain_fcns_from_subtree(_tree->subtree(rx_rf_fe_root(chan) / "gains" / name)), 1 /* high prio */);
+ }
+ return gg;
}
- gain_group::sptr _tx_gain_group(size_t chan){
+
+ gain_group::sptr tx_gain_group(size_t chan){
mboard_chan_pair mcp = tx_chan_to_mcp(chan);
- std::string sd_name = get_tx_subdev_spec(mcp.mboard).at(mcp.chan).sd_name;
- return _tx_dboard(chan)[named_prop_t(DBOARD_PROP_GAIN_GROUP, sd_name)].as<gain_group::sptr>();
+ const subdev_spec_pair_t spec = get_tx_subdev_spec(mcp.mboard).at(mcp.chan);
+ gain_group::sptr gg = gain_group::make();
+ BOOST_FOREACH(const std::string &name, _tree->list(mb_root(mcp.mboard) / "tx_codecs" / spec.db_name / "gains")){
+ gg->register_fcns("ADC-"+name, make_gain_fcns_from_subtree(_tree->subtree(mb_root(mcp.mboard) / "tx_codecs" / spec.db_name / "gains" / name)), 1 /* high prio */);
+ }
+ BOOST_FOREACH(const std::string &name, _tree->list(tx_rf_fe_root(chan) / "gains")){
+ gg->register_fcns(name, make_gain_fcns_from_subtree(_tree->subtree(tx_rf_fe_root(chan) / "gains" / name)), 0 /* low prio */);
+ }
+ return gg;
}
};
diff --git a/host/lib/usrp/tune_helper.cpp b/host/lib/usrp/tune_helper.cpp
deleted file mode 100644
index 264e6c04b..000000000
--- a/host/lib/usrp/tune_helper.cpp
+++ /dev/null
@@ -1,147 +0,0 @@
-//
-// Copyright 2010-2011 Ettus Research LLC
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// 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/tune_helper.hpp>
-#include <uhd/usrp/subdev_props.hpp>
-#include <uhd/usrp/dsp_props.hpp>
-#include <uhd/usrp/dboard_iface.hpp> //unit_t
-#include <uhd/utils/algorithm.hpp>
-#include <cmath>
-
-using namespace uhd;
-using namespace uhd::usrp;
-
-/***********************************************************************
- * Tune Helper Functions
- **********************************************************************/
-static tune_result_t tune_xx_subdev_and_dsp(
- dboard_iface::unit_t unit,
- wax::obj subdev, wax::obj dsp,
- const tune_request_t &tune_request
-){
- wax::obj subdev_freq_proxy = subdev[SUBDEV_PROP_FREQ];
- wax::obj dsp_freq_proxy = dsp[DSP_PROP_FREQ_SHIFT];
-
- //------------------------------------------------------------------
- //-- calculate the LO offset, only used with automatic policy
- //------------------------------------------------------------------
- double lo_offset = 0.0;
- if (subdev[SUBDEV_PROP_USE_LO_OFFSET].as<bool>()){
- //If the local oscillator will be in the passband, use an offset.
- //But constrain the LO offset by the width of the filter bandwidth.
- double rate = dsp[DSP_PROP_HOST_RATE].as<double>();
- double bw = subdev[SUBDEV_PROP_BANDWIDTH].as<double>();
- if (bw > rate) lo_offset = std::min((bw - rate)/2, rate/2);
- }
-
- //------------------------------------------------------------------
- //-- set the RF frequency depending upon the policy
- //------------------------------------------------------------------
- double target_rf_freq = 0.0;
- switch (tune_request.rf_freq_policy){
- case tune_request_t::POLICY_AUTO:
- target_rf_freq = tune_request.target_freq + lo_offset;
- subdev_freq_proxy = target_rf_freq;
- break;
-
- case tune_request_t::POLICY_MANUAL:
- target_rf_freq = tune_request.rf_freq;
- subdev_freq_proxy = target_rf_freq;
- break;
-
- case tune_request_t::POLICY_NONE: break; //does not set
- }
- double actual_rf_freq = subdev_freq_proxy.as<double>();
-
- //------------------------------------------------------------------
- //-- calculate the dsp freq, only used with automatic policy
- //------------------------------------------------------------------
- double target_dsp_freq = actual_rf_freq - tune_request.target_freq;
-
- //invert the sign on the dsp freq given the following conditions
- if (unit == dboard_iface::UNIT_TX) target_dsp_freq *= -1.0;
-
- //------------------------------------------------------------------
- //-- set the dsp frequency depending upon the dsp frequency policy
- //------------------------------------------------------------------
- switch (tune_request.dsp_freq_policy){
- case tune_request_t::POLICY_AUTO:
- dsp_freq_proxy = target_dsp_freq;
- break;
-
- case tune_request_t::POLICY_MANUAL:
- target_dsp_freq = tune_request.dsp_freq;
- dsp_freq_proxy = target_dsp_freq;
- break;
-
- case tune_request_t::POLICY_NONE: break; //does not set
- }
- double actual_dsp_freq = dsp_freq_proxy.as<double>();
-
- //------------------------------------------------------------------
- //-- load and return the tune result
- //------------------------------------------------------------------
- tune_result_t tune_result;
- tune_result.target_rf_freq = target_rf_freq;
- tune_result.actual_rf_freq = actual_rf_freq;
- tune_result.target_dsp_freq = target_dsp_freq;
- tune_result.actual_dsp_freq = actual_dsp_freq;
- return tune_result;
-}
-
-static double derive_freq_from_xx_subdev_and_dsp(
- dboard_iface::unit_t unit, wax::obj subdev, wax::obj dsp
-){
- //extract actual dsp and IF frequencies
- double actual_rf_freq = subdev[SUBDEV_PROP_FREQ].as<double>();
- double actual_dsp_freq = dsp[DSP_PROP_FREQ_SHIFT].as<double>();
-
- //invert the sign on the dsp freq given the following conditions
- if (unit == dboard_iface::UNIT_TX) actual_dsp_freq *= -1.0;
-
- return actual_rf_freq - actual_dsp_freq;
-}
-
-/***********************************************************************
- * RX Tune
- **********************************************************************/
-tune_result_t usrp::tune_rx_subdev_and_dsp(
- wax::obj subdev, wax::obj ddc, const tune_request_t &tune_request
-){
- return tune_xx_subdev_and_dsp(dboard_iface::UNIT_RX, subdev, ddc, tune_request);
-}
-
-double usrp::derive_freq_from_rx_subdev_and_dsp(
- wax::obj subdev, wax::obj ddc
-){
- return derive_freq_from_xx_subdev_and_dsp(dboard_iface::UNIT_RX, subdev, ddc);
-}
-
-/***********************************************************************
- * TX Tune
- **********************************************************************/
-tune_result_t usrp::tune_tx_subdev_and_dsp(
- wax::obj subdev, wax::obj duc, const tune_request_t &tune_request
-){
- return tune_xx_subdev_and_dsp(dboard_iface::UNIT_TX, subdev, duc, tune_request);
-}
-
-double usrp::derive_freq_from_tx_subdev_and_dsp(
- wax::obj subdev, wax::obj duc
-){
- return derive_freq_from_xx_subdev_and_dsp(dboard_iface::UNIT_TX, subdev, duc);
-}
diff --git a/host/lib/usrp/usrp1/CMakeLists.txt b/host/lib/usrp/usrp1/CMakeLists.txt
index c208cfe8c..70bebe502 100644
--- a/host/lib/usrp/usrp1/CMakeLists.txt
+++ b/host/lib/usrp/usrp1/CMakeLists.txt
@@ -26,20 +26,11 @@ LIBUHD_REGISTER_COMPONENT("USRP1" ENABLE_USRP1 ON "ENABLE_LIBUHD;ENABLE_USB" OFF
IF(ENABLE_USRP1)
LIBUHD_APPEND_SOURCES(
- ${CMAKE_CURRENT_SOURCE_DIR}/clock_ctrl.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/clock_ctrl.hpp
${CMAKE_CURRENT_SOURCE_DIR}/codec_ctrl.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/codec_ctrl.hpp
- ${CMAKE_CURRENT_SOURCE_DIR}/codec_impl.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/dboard_impl.cpp
${CMAKE_CURRENT_SOURCE_DIR}/dboard_iface.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/dsp_impl.cpp
${CMAKE_CURRENT_SOURCE_DIR}/io_impl.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/mboard_impl.cpp
${CMAKE_CURRENT_SOURCE_DIR}/soft_time_ctrl.cpp
${CMAKE_CURRENT_SOURCE_DIR}/usrp1_iface.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/usrp1_iface.hpp
${CMAKE_CURRENT_SOURCE_DIR}/usrp1_impl.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/usrp1_impl.hpp
)
ENDIF(ENABLE_USRP1)
diff --git a/host/lib/usrp/usrp1/clock_ctrl.cpp b/host/lib/usrp/usrp1/clock_ctrl.cpp
deleted file mode 100644
index 9edc010dd..000000000
--- a/host/lib/usrp/usrp1/clock_ctrl.cpp
+++ /dev/null
@@ -1,68 +0,0 @@
-//
-// Copyright 2010-2011 Ettus Research LLC
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// 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 "clock_ctrl.hpp"
-#include <uhd/utils/msg.hpp>
-#include <boost/lexical_cast.hpp>
-#include <boost/format.hpp>
-
-using namespace uhd;
-
-/***********************************************************************
- * Constants
- **********************************************************************/
-static const double default_master_clock_rate = 64e6;
-
-/***********************************************************************
- * Clock Control Implementation
- **********************************************************************/
-class usrp1_clock_ctrl_impl : public usrp1_clock_ctrl {
-public:
- usrp1_clock_ctrl_impl(usrp1_iface::sptr iface): _iface(iface){
- this->set_master_clock_freq(default_master_clock_rate);
- try{
- if (not _iface->mb_eeprom["mcr"].empty()){
- UHD_MSG(status) << "Read FPGA clock rate from EEPROM setting." << std::endl;
- const double master_clock_rate = boost::lexical_cast<double>(_iface->mb_eeprom["mcr"]);
- UHD_MSG(status) << boost::format("Initializing FPGA clock to %fMHz...") % (master_clock_rate/1e6) << std::endl;
- this->set_master_clock_freq(master_clock_rate);
- }
- }
- catch(const std::exception &e){
- UHD_MSG(error) << "Error setting FPGA clock rate from EEPROM: " << e.what() << std::endl;
- }
- }
-
- void set_master_clock_freq(double freq){
- _freq = freq;
- }
-
- double get_master_clock_freq(void){
- return _freq;
- }
-
-private:
- usrp1_iface::sptr _iface;
- double _freq;
-};
-
-/***********************************************************************
- * Clock Control Make
- **********************************************************************/
-usrp1_clock_ctrl::sptr usrp1_clock_ctrl::make(usrp1_iface::sptr iface){
- return sptr(new usrp1_clock_ctrl_impl(iface));
-}
diff --git a/host/lib/usrp/usrp1/clock_ctrl.hpp b/host/lib/usrp/usrp1/clock_ctrl.hpp
deleted file mode 100644
index 339d547e6..000000000
--- a/host/lib/usrp/usrp1/clock_ctrl.hpp
+++ /dev/null
@@ -1,57 +0,0 @@
-//
-// Copyright 2010-2011 Ettus Research LLC
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// 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_USRP1_CLOCK_CTRL_HPP
-#define INCLUDED_USRP1_CLOCK_CTRL_HPP
-
-#include "usrp1_iface.hpp"
-#include <boost/shared_ptr.hpp>
-#include <boost/utility.hpp>
-#include <vector>
-
-/*!
- * The usrp1 clock control:
- * - Setup system clocks.
- * - Disable/enable clock lines.
- */
-class usrp1_clock_ctrl : boost::noncopyable{
-public:
- typedef boost::shared_ptr<usrp1_clock_ctrl> sptr;
-
- /*!
- * Make a new clock control object.
- * \param iface the usrp1 iface object
- * \return the clock control object
- */
- static sptr make(usrp1_iface::sptr iface);
-
- /*!
- * Set the rate of the fpga clock line.
- * Note: does not really set, its all software.
- * \param freq the new clock rate in Hz
- */
- virtual void set_master_clock_freq(double freq) = 0;
-
- /*!
- * Get the rate of the fpga clock line.
- * \return the fpga clock rate in Hz
- */
- virtual double get_master_clock_freq(void) = 0;
-
-};
-
-#endif /* INCLUDED_USRP1_CLOCK_CTRL_HPP */
diff --git a/host/lib/usrp/usrp1/codec_ctrl.cpp b/host/lib/usrp/usrp1/codec_ctrl.cpp
index 448135185..c82569ea3 100644
--- a/host/lib/usrp/usrp1/codec_ctrl.cpp
+++ b/host/lib/usrp/usrp1/codec_ctrl.cpp
@@ -16,8 +16,6 @@
//
#include "codec_ctrl.hpp"
-#include "usrp_commands.h"
-#include "clock_ctrl.hpp"
#include "ad9862_regs.hpp"
#include <uhd/utils/log.hpp>
#include <uhd/utils/safe_call.hpp>
@@ -43,9 +41,7 @@ const gain_range_t usrp1_codec_ctrl::rx_pga_gain_range(0, 20, 1);
class usrp1_codec_ctrl_impl : public usrp1_codec_ctrl {
public:
//structors
- usrp1_codec_ctrl_impl(usrp1_iface::sptr iface,
- usrp1_clock_ctrl::sptr clock,
- int spi_slave);
+ usrp1_codec_ctrl_impl(spi_iface::sptr iface, int spi_slave);
~usrp1_codec_ctrl_impl(void);
//aux adc and dac control
@@ -53,7 +49,7 @@ public:
void write_aux_dac(aux_dac_t which, double volts);
//duc control
- void set_duc_freq(double freq);
+ void set_duc_freq(double freq, double);
void enable_tx_digital(bool enb);
//pga gain control
@@ -66,8 +62,7 @@ public:
void bypass_adc_buffers(bool bypass);
private:
- usrp1_iface::sptr _iface;
- usrp1_clock_ctrl::sptr _clock_ctrl;
+ spi_iface::sptr _iface;
int _spi_slave;
ad9862_regs_t _ad9862_regs;
void send_reg(boost::uint8_t addr);
@@ -80,12 +75,8 @@ private:
/***********************************************************************
* Codec Control Structors
**********************************************************************/
-usrp1_codec_ctrl_impl::usrp1_codec_ctrl_impl(usrp1_iface::sptr iface,
- usrp1_clock_ctrl::sptr clock,
- int spi_slave)
-{
+usrp1_codec_ctrl_impl::usrp1_codec_ctrl_impl(spi_iface::sptr iface, int spi_slave){
_iface = iface;
- _clock_ctrl = clock;
_spi_slave = spi_slave;
//soft reset
@@ -381,9 +372,9 @@ double usrp1_codec_ctrl_impl::fine_tune(double codec_rate, double target_freq)
return actual_freq;
}
-void usrp1_codec_ctrl_impl::set_duc_freq(double freq)
+void usrp1_codec_ctrl_impl::set_duc_freq(double freq, double rate)
{
- double codec_rate = _clock_ctrl->get_master_clock_freq() * 2;
+ double codec_rate = rate * 2;
double coarse_freq = coarse_tune(codec_rate, freq);
double fine_freq = fine_tune(codec_rate / 4, freq - coarse_freq);
@@ -421,9 +412,8 @@ void usrp1_codec_ctrl_impl::bypass_adc_buffers(bool bypass) {
/***********************************************************************
* Codec Control Make
**********************************************************************/
-usrp1_codec_ctrl::sptr usrp1_codec_ctrl::make(usrp1_iface::sptr iface,
- usrp1_clock_ctrl::sptr clock,
+usrp1_codec_ctrl::sptr usrp1_codec_ctrl::make(spi_iface::sptr iface,
int spi_slave)
{
- return sptr(new usrp1_codec_ctrl_impl(iface, clock, spi_slave));
+ return sptr(new usrp1_codec_ctrl_impl(iface, spi_slave));
}
diff --git a/host/lib/usrp/usrp1/codec_ctrl.hpp b/host/lib/usrp/usrp1/codec_ctrl.hpp
index 20e4015c5..70f4e0b61 100644
--- a/host/lib/usrp/usrp1/codec_ctrl.hpp
+++ b/host/lib/usrp/usrp1/codec_ctrl.hpp
@@ -18,8 +18,7 @@
#ifndef INCLUDED_USRP1_CODEC_CTRL_HPP
#define INCLUDED_USRP1_CODEC_CTRL_HPP
-#include "usrp1_iface.hpp"
-#include "clock_ctrl.hpp"
+#include <uhd/types/serial.hpp>
#include <uhd/types/ranges.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/utility.hpp>
@@ -38,13 +37,10 @@ public:
/*!
* Make a new clock control object.
- * \param iface the usrp1 iface object
+ * \param iface the spi iface object
* \param spi_slave which spi device
- * \return the clock control object
*/
- static sptr make(usrp1_iface::sptr iface,
- usrp1_clock_ctrl::sptr clock, int spi_slave
- );
+ static sptr make(uhd::spi_iface::sptr iface, int spi_slave);
//! aux adc identifier constants
enum aux_adc_t{
@@ -91,7 +87,7 @@ public:
virtual double get_rx_pga_gain(char which) = 0;
//! Set the TX modulator frequency
- virtual void set_duc_freq(double freq) = 0;
+ virtual void set_duc_freq(double freq, double rate) = 0;
//! Enable or disable the digital part of the DAC
virtual void enable_tx_digital(bool enb) = 0;
diff --git a/host/lib/usrp/usrp1/codec_impl.cpp b/host/lib/usrp/usrp1/codec_impl.cpp
deleted file mode 100644
index 7e4032131..000000000
--- a/host/lib/usrp/usrp1/codec_impl.cpp
+++ /dev/null
@@ -1,159 +0,0 @@
-//
-// Copyright 2010-2011 Ettus Research LLC
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// 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 "usrp1_impl.hpp"
-#include <uhd/exception.hpp>
-#include <uhd/usrp/codec_props.hpp>
-#include <boost/bind.hpp>
-#include <boost/foreach.hpp>
-#include <boost/format.hpp>
-
-using namespace uhd;
-using namespace uhd::usrp;
-
-/***********************************************************************
- * Helper Methods
- **********************************************************************/
-void usrp1_impl::codec_init(void)
-{
- //make proxies
- BOOST_FOREACH(dboard_slot_t dboard_slot, _dboard_slots){
- _rx_codec_proxies[dboard_slot] = wax_obj_proxy::make(
- boost::bind(&usrp1_impl::rx_codec_get, this, _1, _2, dboard_slot),
- boost::bind(&usrp1_impl::rx_codec_set, this, _1, _2, dboard_slot));
-
- _tx_codec_proxies[dboard_slot] = wax_obj_proxy::make(
- boost::bind(&usrp1_impl::tx_codec_get, this, _1, _2, dboard_slot),
- boost::bind(&usrp1_impl::tx_codec_set, this, _1, _2, dboard_slot));
- }
-}
-
-/***********************************************************************
- * RX Codec Properties
- **********************************************************************/
-static const std::string adc_pga_gain_name = "PGA";
-
-void usrp1_impl::rx_codec_get(const wax::obj &key_, wax::obj &val, dboard_slot_t dboard_slot)
-{
- named_prop_t key = named_prop_t::extract(key_);
-
- //handle the get request conditioned on the key
- switch(key.as<codec_prop_t>()) {
- case CODEC_PROP_NAME:
- val = str(boost::format("usrp1 adc - ad9862 - slot %c") % char(dboard_slot));
- return;
-
- case CODEC_PROP_OTHERS:
- val = prop_names_t();
- return;
-
- case CODEC_PROP_GAIN_NAMES:
- val = prop_names_t(1, adc_pga_gain_name);
- return;
-
- case CODEC_PROP_GAIN_RANGE:
- UHD_ASSERT_THROW(key.name == adc_pga_gain_name);
- val = usrp1_codec_ctrl::rx_pga_gain_range;
- return;
-
- case CODEC_PROP_GAIN_I:
- UHD_ASSERT_THROW(key.name == adc_pga_gain_name);
- val = _codec_ctrls[dboard_slot]->get_rx_pga_gain('A');
- return;
-
- case CODEC_PROP_GAIN_Q:
- UHD_ASSERT_THROW(key.name == adc_pga_gain_name);
- val = _codec_ctrls[dboard_slot]->get_rx_pga_gain('B');
- return;
-
- default: UHD_THROW_PROP_GET_ERROR();
- }
-}
-
-void usrp1_impl::rx_codec_set(const wax::obj &key_, const wax::obj &val, dboard_slot_t dboard_slot)
-{
- named_prop_t key = named_prop_t::extract(key_);
-
- //handle the set request conditioned on the key
- switch(key.as<codec_prop_t>()) {
- case CODEC_PROP_GAIN_I:
- UHD_ASSERT_THROW(key.name == adc_pga_gain_name);
- _codec_ctrls[dboard_slot]->set_rx_pga_gain(val.as<double>(), 'A');
- return;
-
- case CODEC_PROP_GAIN_Q:
- UHD_ASSERT_THROW(key.name == adc_pga_gain_name);
- _codec_ctrls[dboard_slot]->set_rx_pga_gain(val.as<double>(), 'B');
- return;
-
- default: UHD_THROW_PROP_SET_ERROR();
- }
-}
-
-/***********************************************************************
- * TX Codec Properties
- **********************************************************************/
-static const std::string dac_pga_gain_name = "PGA";
-
-void usrp1_impl::tx_codec_get(const wax::obj &key_, wax::obj &val, dboard_slot_t dboard_slot)
-{
- named_prop_t key = named_prop_t::extract(key_);
-
- //handle the get request conditioned on the key
- switch(key.as<codec_prop_t>()) {
- case CODEC_PROP_NAME:
- val = str(boost::format("usrp1 dac - ad9862 - slot %c") % char(dboard_slot));
- return;
-
- case CODEC_PROP_OTHERS:
- val = prop_names_t();
- return;
-
- case CODEC_PROP_GAIN_NAMES:
- val = prop_names_t(1, dac_pga_gain_name);
- return;
-
- case CODEC_PROP_GAIN_RANGE:
- UHD_ASSERT_THROW(key.name == dac_pga_gain_name);
- val = usrp1_codec_ctrl::tx_pga_gain_range;
- return;
-
- case CODEC_PROP_GAIN_I: //only one gain for I and Q
- case CODEC_PROP_GAIN_Q:
- UHD_ASSERT_THROW(key.name == dac_pga_gain_name);
- val = _codec_ctrls[dboard_slot]->get_tx_pga_gain();
- return;
-
- default: UHD_THROW_PROP_GET_ERROR();
- }
-}
-
-void usrp1_impl::tx_codec_set(const wax::obj &key_, const wax::obj &val, dboard_slot_t dboard_slot)
-{
- named_prop_t key = named_prop_t::extract(key_);
-
- //handle the set request conditioned on the key
- switch(key.as<codec_prop_t>()){
- case CODEC_PROP_GAIN_I: //only one gain for I and Q
- case CODEC_PROP_GAIN_Q:
- UHD_ASSERT_THROW(key.name == dac_pga_gain_name);
- _codec_ctrls[dboard_slot]->set_tx_pga_gain(val.as<double>());
- return;
-
- default: UHD_THROW_PROP_SET_ERROR();
- }
-}
diff --git a/host/lib/usrp/usrp1/dboard_iface.cpp b/host/lib/usrp/usrp1/dboard_iface.cpp
index 3f3a98b7a..449ec64fe 100644
--- a/host/lib/usrp/usrp1/dboard_iface.cpp
+++ b/host/lib/usrp/usrp1/dboard_iface.cpp
@@ -20,7 +20,6 @@
#include "fpga_regs_common.h"
#include "usrp_spi_defs.h"
#include "fpga_regs_standard.h"
-#include "clock_ctrl.hpp"
#include "codec_ctrl.hpp"
#include <uhd/usrp/dboard_iface.hpp>
#include <uhd/types/dict.hpp>
@@ -38,16 +37,16 @@ class usrp1_dboard_iface : public dboard_iface {
public:
usrp1_dboard_iface(usrp1_iface::sptr iface,
- usrp1_clock_ctrl::sptr clock,
usrp1_codec_ctrl::sptr codec,
usrp1_impl::dboard_slot_t dboard_slot,
+ const double master_clock_rate,
const dboard_id_t &rx_dboard_id
):
_dboard_slot(dboard_slot),
+ _master_clock_rate(master_clock_rate),
_rx_dboard_id(rx_dboard_id)
{
_iface = iface;
- _clock = clock;
_codec = codec;
//init the clock rate shadows
@@ -103,24 +102,24 @@ public:
private:
usrp1_iface::sptr _iface;
- usrp1_clock_ctrl::sptr _clock;
usrp1_codec_ctrl::sptr _codec;
uhd::dict<unit_t, double> _clock_rates;
const usrp1_impl::dboard_slot_t _dboard_slot;
- const dboard_id_t &_rx_dboard_id;
+ const double _master_clock_rate;
+ const dboard_id_t _rx_dboard_id;
};
/***********************************************************************
* Make Function
**********************************************************************/
dboard_iface::sptr usrp1_impl::make_dboard_iface(usrp1_iface::sptr iface,
- usrp1_clock_ctrl::sptr clock,
usrp1_codec_ctrl::sptr codec,
- dboard_slot_t dboard_slot,
+ usrp1_impl::dboard_slot_t dboard_slot,
+ const double master_clock_rate,
const dboard_id_t &rx_dboard_id
){
return dboard_iface::sptr(new usrp1_dboard_iface(
- iface, clock, codec, dboard_slot, rx_dboard_id
+ iface, codec, dboard_slot, master_clock_rate, rx_dboard_id
));
}
@@ -141,7 +140,7 @@ void usrp1_dboard_iface::set_clock_rate(unit_t unit, double rate)
_clock_rates[unit] = rate;
if (unit == UNIT_RX && _rx_dboard_id == dbsrx_classic_id){
- size_t divider = size_t(_clock->get_master_clock_freq()/rate);
+ size_t divider = size_t(_master_clock_rate/rate);
switch(_dboard_slot){
case usrp1_impl::DBOARD_SLOT_A:
_iface->poke32(FR_RX_A_REFCLK, (divider & 0x7f) | 0x80);
@@ -159,10 +158,10 @@ std::vector<double> usrp1_dboard_iface::get_clock_rates(unit_t unit)
std::vector<double> rates;
if (unit == UNIT_RX && _rx_dboard_id == dbsrx_classic_id){
for (size_t div = 1; div <= 127; div++)
- rates.push_back(_clock->get_master_clock_freq() / div);
+ rates.push_back(_master_clock_rate / div);
}
else{
- rates.push_back(_clock->get_master_clock_freq());
+ rates.push_back(_master_clock_rate);
}
return rates;
}
@@ -178,7 +177,7 @@ void usrp1_dboard_iface::set_clock_enabled(unit_t, bool)
}
double usrp1_dboard_iface::get_codec_rate(unit_t){
- return _clock->get_master_clock_freq();
+ return _master_clock_rate;
}
/***********************************************************************
diff --git a/host/lib/usrp/usrp1/dboard_impl.cpp b/host/lib/usrp/usrp1/dboard_impl.cpp
deleted file mode 100644
index df0bb6261..000000000
--- a/host/lib/usrp/usrp1/dboard_impl.cpp
+++ /dev/null
@@ -1,218 +0,0 @@
-//
-// Copyright 2010-2011 Ettus Research LLC
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// 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 "usrp1_impl.hpp"
-#include "usrp_i2c_addr.h"
-#include <uhd/usrp/dsp_utils.hpp>
-#include <uhd/usrp/misc_utils.hpp>
-#include <uhd/exception.hpp>
-#include <uhd/usrp/dboard_props.hpp>
-#include <uhd/usrp/subdev_props.hpp>
-#include <boost/bind.hpp>
-#include <boost/foreach.hpp>
-#include <boost/format.hpp>
-#include <iostream>
-
-using namespace uhd;
-using namespace uhd::usrp;
-
-/***********************************************************************
- * Helper Functions
- **********************************************************************/
-static boost::uint8_t get_rx_ee_addr(usrp1_impl::dboard_slot_t dboard_slot){
- switch(dboard_slot){
- case usrp1_impl::DBOARD_SLOT_A: return I2C_ADDR_RX_A;
- case usrp1_impl::DBOARD_SLOT_B: return I2C_ADDR_RX_B;
- default: UHD_THROW_INVALID_CODE_PATH();
- }
-}
-
-static boost::uint8_t get_tx_ee_addr(usrp1_impl::dboard_slot_t dboard_slot){
- switch(dboard_slot){
- case usrp1_impl::DBOARD_SLOT_A: return I2C_ADDR_TX_A;
- case usrp1_impl::DBOARD_SLOT_B: return I2C_ADDR_TX_B;
- default: UHD_THROW_INVALID_CODE_PATH();
- }
-}
-
-/***********************************************************************
- * Dboard Initialization
- **********************************************************************/
-void usrp1_impl::dboard_init(void)
-{
- BOOST_FOREACH(dboard_slot_t dboard_slot, _dboard_slots){
-
- //read the tx and rx dboard eeproms
- _rx_db_eeproms[dboard_slot].load(*_iface, get_rx_ee_addr(dboard_slot));
- _tx_db_eeproms[dboard_slot].load(*_iface, get_tx_ee_addr(dboard_slot));
- _gdb_eeproms[dboard_slot].load(*_iface, get_tx_ee_addr(dboard_slot) ^ 5);
-
- //create a new dboard interface and manager
- _dboard_ifaces[dboard_slot] = make_dboard_iface(
- _iface, _clock_ctrl, _codec_ctrls[dboard_slot],
- dboard_slot, _rx_db_eeproms[dboard_slot].id
- );
-
- _dboard_managers[dboard_slot] = dboard_manager::make(
- _rx_db_eeproms[dboard_slot].id,
- ((_gdb_eeproms[dboard_slot].id == dboard_id_t::none())? _tx_db_eeproms[dboard_slot] : _gdb_eeproms[dboard_slot]).id,
- _dboard_ifaces[dboard_slot]
- );
-
- //setup the dboard proxies
- _rx_dboard_proxies[dboard_slot] = wax_obj_proxy::make(
- boost::bind(&usrp1_impl::rx_dboard_get, this, _1, _2, dboard_slot),
- boost::bind(&usrp1_impl::rx_dboard_set, this, _1, _2, dboard_slot));
-
- _tx_dboard_proxies[dboard_slot] = wax_obj_proxy::make(
- boost::bind(&usrp1_impl::tx_dboard_get, this, _1, _2, dboard_slot),
- boost::bind(&usrp1_impl::tx_dboard_set, this, _1, _2, dboard_slot));
- }
-
-}
-
-/***********************************************************************
- * RX Dboard Get
- **********************************************************************/
-void usrp1_impl::rx_dboard_get(const wax::obj &key_, wax::obj &val, dboard_slot_t dboard_slot)
-{
- named_prop_t key = named_prop_t::extract(key_);
-
- //handle the get request conditioned on the key
- switch(key.as<dboard_prop_t>()){
- case DBOARD_PROP_NAME:
- val = str(boost::format("usrp1 dboard (rx unit) - %c") % char(dboard_slot));
- return;
-
- case DBOARD_PROP_SUBDEV:
- val = _dboard_managers[dboard_slot]->get_rx_subdev(key.name);
- return;
-
- case DBOARD_PROP_SUBDEV_NAMES:
- val = _dboard_managers[dboard_slot]->get_rx_subdev_names();
- return;
-
- case DBOARD_PROP_DBOARD_EEPROM:
- val = _rx_db_eeproms[dboard_slot];
- return;
-
- case DBOARD_PROP_DBOARD_IFACE:
- val = _dboard_ifaces[dboard_slot];
- return;
-
- case DBOARD_PROP_CODEC:
- val = _rx_codec_proxies[dboard_slot]->get_link();
- return;
-
- case DBOARD_PROP_GAIN_GROUP:
- val = make_gain_group(
- _rx_db_eeproms[dboard_slot].id,
- _dboard_managers[dboard_slot]->get_rx_subdev(key.name),
- _rx_codec_proxies[dboard_slot]->get_link(),
- GAIN_GROUP_POLICY_RX
- );
- return;
-
- default: UHD_THROW_PROP_GET_ERROR();
- }
-}
-
-/***********************************************************************
- * RX Dboard Set
- **********************************************************************/
-void usrp1_impl::rx_dboard_set(const wax::obj &key, const wax::obj &val, dboard_slot_t dboard_slot)
-{
- switch(key.as<dboard_prop_t>()) {
- case DBOARD_PROP_DBOARD_EEPROM:
- _rx_db_eeproms[dboard_slot] = val.as<dboard_eeprom_t>();
- _rx_db_eeproms[dboard_slot].store(*_iface, get_rx_ee_addr(dboard_slot));
- return;
-
- default:
- UHD_THROW_PROP_SET_ERROR();
- }
-}
-
-/***********************************************************************
- * TX Dboard Get
- **********************************************************************/
-void usrp1_impl::tx_dboard_get(const wax::obj &key_, wax::obj &val, dboard_slot_t dboard_slot)
-{
- named_prop_t key = named_prop_t::extract(key_);
-
- //handle the get request conditioned on the key
- switch(key.as<dboard_prop_t>()){
- case DBOARD_PROP_NAME:
- val = str(boost::format("usrp1 dboard (tx unit) - %c") % char(dboard_slot));
- return;
-
- case DBOARD_PROP_SUBDEV:
- val = _dboard_managers[dboard_slot]->get_tx_subdev(key.name);
- return;
-
- case DBOARD_PROP_SUBDEV_NAMES:
- val = _dboard_managers[dboard_slot]->get_tx_subdev_names();
- return;
-
- case DBOARD_PROP_DBOARD_EEPROM:
- val = _tx_db_eeproms[dboard_slot];
- return;
-
- case DBOARD_PROP_GBOARD_EEPROM:
- val = _gdb_eeproms[dboard_slot];
- return;
-
- case DBOARD_PROP_DBOARD_IFACE:
- val = _dboard_ifaces[dboard_slot];
- return;
-
- case DBOARD_PROP_CODEC:
- val = _tx_codec_proxies[dboard_slot]->get_link();
- return;
-
- case DBOARD_PROP_GAIN_GROUP:
- val = make_gain_group(
- _tx_db_eeproms[dboard_slot].id,
- _dboard_managers[dboard_slot]->get_tx_subdev(key.name),
- _tx_codec_proxies[dboard_slot]->get_link(),
- GAIN_GROUP_POLICY_TX
- );
- return;
-
- default: UHD_THROW_PROP_GET_ERROR();
- }
-}
-
-/***********************************************************************
- * TX Dboard Set
- **********************************************************************/
-void usrp1_impl::tx_dboard_set(const wax::obj &key, const wax::obj &val, dboard_slot_t dboard_slot)
-{
- switch(key.as<dboard_prop_t>()) {
- case DBOARD_PROP_DBOARD_EEPROM:
- _tx_db_eeproms[dboard_slot] = val.as<dboard_eeprom_t>();
- _tx_db_eeproms[dboard_slot].store(*_iface, get_tx_ee_addr(dboard_slot));
- return;
-
- case DBOARD_PROP_GBOARD_EEPROM:
- _gdb_eeproms[dboard_slot] = val.as<dboard_eeprom_t>();
- _gdb_eeproms[dboard_slot].store(*_iface, get_tx_ee_addr(dboard_slot) ^ 5);
- return;
-
- default: UHD_THROW_PROP_SET_ERROR();
- }
-}
diff --git a/host/lib/usrp/usrp1/dsp_impl.cpp b/host/lib/usrp/usrp1/dsp_impl.cpp
deleted file mode 100644
index 0bddc49f0..000000000
--- a/host/lib/usrp/usrp1/dsp_impl.cpp
+++ /dev/null
@@ -1,222 +0,0 @@
-//
-// Copyright 2010-2011 Ettus Research LLC
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// 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 "usrp1_impl.hpp"
-#include "fpga_regs_standard.h"
-#include <uhd/utils/msg.hpp>
-#include <uhd/usrp/dsp_utils.hpp>
-#include <uhd/usrp/dsp_props.hpp>
-#include <boost/bind.hpp>
-#include <boost/format.hpp>
-#include <boost/lexical_cast.hpp>
-#include <boost/assign/list_of.hpp>
-#include <cmath>
-
-using namespace uhd;
-using namespace uhd::usrp;
-
-/***********************************************************************
- * RX DDC Initialization
- **********************************************************************/
-void usrp1_impl::rx_dsp_init(void)
-{
- for (size_t i = 0; i < this->get_num_ddcs(); i++){
- _rx_dsp_proxies[str(boost::format("DSP%d")%i)] = wax_obj_proxy::make(
- boost::bind(&usrp1_impl::rx_dsp_get, this, _1, _2, i),
- boost::bind(&usrp1_impl::rx_dsp_set, this, _1, _2, i)
- );
- rx_dsp_set(DSP_PROP_HOST_RATE, _clock_ctrl->get_master_clock_freq() / 16, i);
- }
-}
-
-/***********************************************************************
- * RX DDC Get
- **********************************************************************/
-void usrp1_impl::rx_dsp_get(const wax::obj &key_, wax::obj &val, size_t which_dsp){
- named_prop_t key = named_prop_t::extract(key_);
-
- switch(key.as<dsp_prop_t>()){
- case DSP_PROP_NAME:
- val = str(boost::format("usrp1 ddc%d %s")
- % which_dsp
- % (this->has_rx_halfband()? "+ hb" : "")
- );
- return;
-
- case DSP_PROP_OTHERS:
- val = prop_names_t();
- return;
-
- case DSP_PROP_FREQ_SHIFT:
- val = _rx_dsp_freqs[which_dsp];
- return;
-
- case DSP_PROP_CODEC_RATE:
- val = _clock_ctrl->get_master_clock_freq();
- return;
-
- case DSP_PROP_HOST_RATE:
- val = _clock_ctrl->get_master_clock_freq()/_rx_dsp_decim;
- return;
-
- default: UHD_THROW_PROP_GET_ERROR();
- }
-
-}
-
-/***********************************************************************
- * RX DDC Set
- **********************************************************************/
-void usrp1_impl::rx_dsp_set(const wax::obj &key_, const wax::obj &val, size_t which_dsp){
- named_prop_t key = named_prop_t::extract(key_);
-
- switch(key.as<dsp_prop_t>()) {
- case DSP_PROP_FREQ_SHIFT: {
- double new_freq = val.as<double>();
- boost::uint32_t reg_word = dsp_type1::calc_cordic_word_and_update(
- new_freq, _clock_ctrl->get_master_clock_freq());
-
- static const boost::uint32_t dsp_index_to_reg_val[4] = {
- FR_RX_FREQ_0, FR_RX_FREQ_1, FR_RX_FREQ_2, FR_RX_FREQ_3
- };
- _iface->poke32(dsp_index_to_reg_val[which_dsp], ~reg_word + 1);
- _rx_dsp_freqs[which_dsp] = new_freq;
- return;
- }
-
- case DSP_PROP_HOST_RATE:
- if (which_dsp != 0) return; //only for dsp[0] as this is vectorized
- {
- size_t rate = size_t(_clock_ctrl->get_master_clock_freq() / val.as<double>());
-
- //clip the rate to something in range:
- rate = std::min<size_t>(std::max<size_t>(rate, 4), 256);
-
- _rx_dsp_decim = rate;
- //TODO Poll every 100ms. Make it selectable?
- _rx_samps_per_poll_interval = size_t(0.1 * _clock_ctrl->get_master_clock_freq() / rate);
-
- bool s = this->disable_rx();
- _iface->poke32(FR_DECIM_RATE, _rx_dsp_decim/2 - 1);
- this->restore_rx(s);
- }
- this->update_xport_channel_mapping(); //rate changed -> update
- return;
-
- case DSP_PROP_STREAM_CMD:
- if (which_dsp != 0) return; //only for dsp[0] as this is vectorized
- _soft_time_ctrl->issue_stream_cmd(val.as<stream_cmd_t>());
- return;
-
- default: UHD_THROW_PROP_SET_ERROR();
- }
-
-}
-
-/***********************************************************************
- * TX DUC Initialization
- **********************************************************************/
-void usrp1_impl::tx_dsp_init(void)
-{
- for (size_t i = 0; i < this->get_num_ducs(); i++){
- _tx_dsp_proxies[str(boost::format("DSP%d")%i)] = wax_obj_proxy::make(
- boost::bind(&usrp1_impl::tx_dsp_get, this, _1, _2, i),
- boost::bind(&usrp1_impl::tx_dsp_set, this, _1, _2, i)
- );
- tx_dsp_set(DSP_PROP_HOST_RATE, _clock_ctrl->get_master_clock_freq() / 16, i);
- }
-}
-
-/***********************************************************************
- * TX DUC Get
- **********************************************************************/
-void usrp1_impl::tx_dsp_get(const wax::obj &key_, wax::obj &val, size_t which_dsp){
- named_prop_t key = named_prop_t::extract(key_);
-
- switch(key.as<dsp_prop_t>()) {
- case DSP_PROP_NAME:
- val = str(boost::format("usrp1 duc%d %s")
- % which_dsp
- % (this->has_tx_halfband()? "+ hb" : "")
- );
- return;
-
- case DSP_PROP_OTHERS:
- val = prop_names_t(); //empty
- return;
-
- case DSP_PROP_FREQ_SHIFT:
- val = _tx_dsp_freqs[which_dsp];
- return;
-
- case DSP_PROP_CODEC_RATE:
- val = _clock_ctrl->get_master_clock_freq();
- return;
-
- case DSP_PROP_HOST_RATE:
- val = _clock_ctrl->get_master_clock_freq() / _tx_dsp_interp;
- return;
-
- default: UHD_THROW_PROP_GET_ERROR();
- }
-
-}
-
-/***********************************************************************
- * TX DUC Set
- **********************************************************************/
-void usrp1_impl::tx_dsp_set(const wax::obj &key_, const wax::obj &val, size_t which_dsp){
- named_prop_t key = named_prop_t::extract(key_);
-
- switch(key.as<dsp_prop_t>()) {
-
- case DSP_PROP_FREQ_SHIFT: {
- double new_freq = val.as<double>();
-
- //map the freq shift key to a subdev spec to a particular codec chip
- std::string db_name = _tx_subdev_spec.at(which_dsp).db_name;
- if (db_name == "A") _codec_ctrls[DBOARD_SLOT_A]->set_duc_freq(new_freq);
- if (db_name == "B") _codec_ctrls[DBOARD_SLOT_B]->set_duc_freq(new_freq);
-
- _tx_dsp_freqs[which_dsp] = new_freq;
- return;
- }
-
- case DSP_PROP_HOST_RATE:
- if (which_dsp != 0) return; //only for dsp[0] as this is vectorized
- {
- size_t rate = size_t(_clock_ctrl->get_master_clock_freq() / val.as<double>());
-
- //clip the rate to something in range:
- rate = std::min<size_t>(std::max<size_t>(rate, 4), 256);
-
- _tx_dsp_interp = rate;
-
- //TODO Poll every 100ms. Make it selectable?
- _tx_samps_per_poll_interval = size_t(0.1 * _clock_ctrl->get_master_clock_freq() / rate);
-
- bool s = this->disable_tx();
- _iface->poke32(FR_INTERP_RATE, _tx_dsp_interp/2 - 1);
- this->restore_tx(s);
- }
- this->update_xport_channel_mapping(); //rate changed -> update
- return;
-
- default: UHD_THROW_PROP_SET_ERROR();
- }
-
-}
diff --git a/host/lib/usrp/usrp1/io_impl.cpp b/host/lib/usrp/usrp1/io_impl.cpp
index 90ed17cd8..e81b00d1c 100644
--- a/host/lib/usrp/usrp1/io_impl.cpp
+++ b/host/lib/usrp/usrp1/io_impl.cpp
@@ -15,26 +15,27 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
+#include "validate_subdev_spec.hpp"
#define SRPH_DONT_CHECK_SEQUENCE
#include "../../transport/super_recv_packet_handler.hpp"
#include "../../transport/super_send_packet_handler.hpp"
+#include "usrp1_calc_mux.hpp"
+#include "fpga_regs_standard.h"
#include "usrp_commands.h"
#include "usrp1_impl.hpp"
#include <uhd/utils/msg.hpp>
+#include <uhd/utils/tasks.hpp>
#include <uhd/utils/safe_call.hpp>
-#include <uhd/utils/thread_priority.hpp>
-#include <uhd/usrp/dsp_props.hpp>
#include <uhd/transport/bounded_buffer.hpp>
+#include <boost/math/special_functions/sign.hpp>
+#include <boost/math/special_functions/round.hpp>
+#include <boost/thread/thread.hpp>
#include <boost/bind.hpp>
#include <boost/format.hpp>
-#include <boost/asio.hpp>
-#include <boost/bind.hpp>
-#include <boost/thread.hpp>
using namespace uhd;
using namespace uhd::usrp;
using namespace uhd::transport;
-namespace asio = boost::asio;
static const size_t alignment_padding = 512;
@@ -124,8 +125,6 @@ static void usrp1_bs_vrt_unpacker(
struct usrp1_impl::io_impl{
io_impl(zero_copy_if::sptr data_transport):
data_transport(data_transport),
- underflow_poll_samp_count(0),
- overflow_poll_samp_count(0),
curr_buff(offset_send_buffer(data_transport->get_send_buff())),
omsb(boost::bind(&usrp1_impl::io_impl::commit_send_buff, this, _1, _2, _3))
{
@@ -142,10 +141,6 @@ struct usrp1_impl::io_impl{
sph::recv_packet_handler recv_handler;
sph::send_packet_handler send_handler;
- //state management for overflow and underflow
- size_t underflow_poll_samp_count;
- size_t overflow_poll_samp_count;
-
//wrapper around the actual send buffer interface
//all of this to ensure only aligned lengths are committed
//NOTE: you must commit before getting a new buffer
@@ -162,6 +157,9 @@ struct usrp1_impl::io_impl{
//make a new managed buffer with the offset buffs
return omsb.get_new(curr_buff, next_buff);
}
+
+ task::sptr vandal_task;
+ boost::system_time last_send_time;
};
/*!
@@ -230,51 +228,219 @@ void usrp1_impl::io_init(void){
_io_impl = UHD_PIMPL_MAKE(io_impl, (_data_transport));
- _soft_time_ctrl = soft_time_ctrl::make(
- boost::bind(&usrp1_impl::rx_stream_on_off, this, _1)
- );
-
- this->enable_tx(true); //always enabled
- rx_stream_on_off(false);
- _io_impl->flush_send_buff();
-
- //update mapping here since it didnt b4 when io init not called first
- update_xport_channel_mapping();
-}
-
-void usrp1_impl::update_xport_channel_mapping(void){
- if (_io_impl.get() == NULL) return; //not inited yet
+ //create a new vandal thread to poll xerflow conditions
+ _io_impl->vandal_task = task::make(boost::bind(
+ &usrp1_impl::vandal_conquest_loop, this
+ ));
- //set all of the relevant properties on the handler
- boost::mutex::scoped_lock recv_lock = _io_impl->recv_handler.get_scoped_lock();
+ //init some handler stuff
+ _io_impl->recv_handler.set_tick_rate(_master_clock_rate);
_io_impl->recv_handler.set_vrt_unpacker(&usrp1_bs_vrt_unpacker);
- _io_impl->recv_handler.set_tick_rate(_clock_ctrl->get_master_clock_freq());
- _io_impl->recv_handler.set_samp_rate(_rx_dsp_proxies[_rx_dsp_proxies.keys().at(0)]->get_link()[DSP_PROP_HOST_RATE].as<double>());
_io_impl->recv_handler.set_xport_chan_get_buff(0, boost::bind(
&uhd::transport::zero_copy_if::get_recv_buff, _io_impl->data_transport, _1
));
- _io_impl->recv_handler.set_converter(_rx_otw_type, _rx_subdev_spec.size());
-
- //set all of the relevant properties on the handler
- boost::mutex::scoped_lock send_lock = _io_impl->send_handler.get_scoped_lock();
+ _io_impl->send_handler.set_tick_rate(_master_clock_rate);
_io_impl->send_handler.set_vrt_packer(&usrp1_bs_vrt_packer);
- _io_impl->send_handler.set_tick_rate(_clock_ctrl->get_master_clock_freq());
- _io_impl->send_handler.set_samp_rate(_tx_dsp_proxies[_tx_dsp_proxies.keys().at(0)]->get_link()[DSP_PROP_HOST_RATE].as<double>());
_io_impl->send_handler.set_xport_chan_get_buff(0, boost::bind(
&usrp1_impl::io_impl::get_send_buff, _io_impl.get(), _1
));
- _io_impl->send_handler.set_converter(_tx_otw_type, _tx_subdev_spec.size());
- _io_impl->send_handler.set_max_samples_per_packet(get_max_send_samps_per_packet());
+
+ //init as disabled, then call the real function (uses restore)
+ this->enable_rx(false);
+ this->enable_tx(false);
+ rx_stream_on_off(false);
+ tx_stream_on_off(false);
+ _io_impl->flush_send_buff();
}
void usrp1_impl::rx_stream_on_off(bool enb){
- this->enable_rx(enb);
+ this->restore_rx(enb);
//drain any junk in the receive transport after stop streaming command
while(not enb and _data_transport->get_recv_buff().get() != NULL){
/* NOP */
}
}
+void usrp1_impl::tx_stream_on_off(bool enb){
+ _io_impl->last_send_time = boost::get_system_time();
+ if (_tx_enabled and not enb) _io_impl->flush_send_buff();
+ this->restore_tx(enb);
+}
+
+/*!
+ * Casually poll the overflow and underflow registers.
+ * On an underflow, push an async message into the queue and print.
+ * On an overflow, interleave an inline message into recv and print.
+ * This procedure creates "soft" inline and async user messages.
+ */
+void usrp1_impl::vandal_conquest_loop(void){
+
+ //initialize the async metadata
+ async_metadata_t async_metadata;
+ async_metadata.channel = 0;
+ async_metadata.has_time_spec = true;
+ async_metadata.event_code = async_metadata_t::EVENT_CODE_UNDERFLOW;
+
+ //initialize the inline metadata
+ rx_metadata_t inline_metadata;
+ inline_metadata.has_time_spec = true;
+ inline_metadata.error_code = rx_metadata_t::ERROR_CODE_OVERFLOW;
+
+ //start the polling loop...
+ try{ while (not boost::this_thread::interruption_requested()){
+ boost::uint8_t underflow = 0, overflow = 0;
+
+ //shutoff transmit if it has been too long since send() was called
+ if (_tx_enabled and (boost::get_system_time() - _io_impl->last_send_time) > boost::posix_time::milliseconds(100)){
+ this->tx_stream_on_off(false);
+ }
+
+ //always poll regardless of enabled so we can clear the conditions
+ _fx2_ctrl->usrp_control_read(
+ VRQ_GET_STATUS, 0, GS_TX_UNDERRUN, &underflow, sizeof(underflow)
+ );
+ _fx2_ctrl->usrp_control_read(
+ VRQ_GET_STATUS, 0, GS_RX_OVERRUN, &overflow, sizeof(overflow)
+ );
+
+ //handle message generation for xerflow conditions
+ if (_tx_enabled and underflow){
+ async_metadata.time_spec = _soft_time_ctrl->get_time();
+ _soft_time_ctrl->get_async_queue().push_with_pop_on_full(async_metadata);
+ UHD_MSG(fastpath) << "U";
+ }
+ if (_rx_enabled and overflow){
+ inline_metadata.time_spec = _soft_time_ctrl->get_time();
+ _soft_time_ctrl->get_inline_queue().push_with_pop_on_full(inline_metadata);
+ UHD_MSG(fastpath) << "O";
+ }
+
+ boost::this_thread::sleep(boost::posix_time::milliseconds(50));
+ }}
+ catch(const boost::thread_interrupted &){} //normal exit condition
+ catch(const std::exception &e){
+ UHD_MSG(error) << "The vandal caught an unexpected exception " << e.what() << std::endl;
+ }
+}
+
+/***********************************************************************
+ * Properties callback methods below
+ **********************************************************************/
+void usrp1_impl::update_rx_subdev_spec(const uhd::usrp::subdev_spec_t &spec){
+ boost::mutex::scoped_lock lock = _io_impl->recv_handler.get_scoped_lock();
+
+ //sanity checking
+ validate_subdev_spec(_tree, spec, "rx");
+
+ _rx_subdev_spec = spec; //shadow
+ _io_impl->recv_handler.resize(spec.size());
+ _io_impl->recv_handler.set_converter(_rx_otw_type, spec.size());
+
+ //set the mux and set the number of rx channels
+ std::vector<mapping_pair_t> mapping;
+ BOOST_FOREACH(const subdev_spec_pair_t &pair, spec){
+ const std::string conn = _tree->access<std::string>(str(boost::format(
+ "/mboards/0/dboards/%s/rx_frontends/%s/connection"
+ ) % pair.db_name % pair.sd_name)).get();
+ mapping.push_back(std::make_pair(pair.db_name, conn));
+ }
+ bool s = this->disable_rx();
+ _iface->poke32(FR_RX_MUX, calc_rx_mux(mapping));
+ this->restore_rx(s);
+}
+
+void usrp1_impl::update_tx_subdev_spec(const uhd::usrp::subdev_spec_t &spec){
+ boost::mutex::scoped_lock lock = _io_impl->send_handler.get_scoped_lock();
+
+ //sanity checking
+ validate_subdev_spec(_tree, spec, "tx");
+
+ _tx_subdev_spec = spec; //shadow
+ _io_impl->send_handler.resize(spec.size());
+ _io_impl->send_handler.set_converter(_tx_otw_type, spec.size());
+
+ //set the mux and set the number of tx channels
+ std::vector<mapping_pair_t> mapping;
+ BOOST_FOREACH(const subdev_spec_pair_t &pair, spec){
+ const std::string conn = _tree->access<std::string>(str(boost::format(
+ "/mboards/0/dboards/%s/tx_frontends/%s/connection"
+ ) % pair.db_name % pair.sd_name)).get();
+ mapping.push_back(std::make_pair(pair.db_name, conn));
+ }
+ bool s = this->disable_tx();
+ _iface->poke32(FR_TX_MUX, calc_tx_mux(mapping));
+ this->restore_tx(s);
+
+ //if the spec changes size, so does the max samples per packet...
+ _io_impl->send_handler.set_max_samples_per_packet(get_max_send_samps_per_packet());
+}
+
+double usrp1_impl::update_rx_samp_rate(const double samp_rate){
+ boost::mutex::scoped_lock lock = _io_impl->recv_handler.get_scoped_lock();
+
+ const size_t rate = uhd::clip<size_t>(
+ boost::math::iround(_master_clock_rate / samp_rate), size_t(std::ceil(_master_clock_rate / 8e6)), 256
+ );
+
+ bool s = this->disable_rx();
+ _iface->poke32(FR_DECIM_RATE, rate/2 - 1);
+ this->restore_rx(s);
+
+ _io_impl->recv_handler.set_samp_rate(_master_clock_rate / rate);
+ return _master_clock_rate / rate;
+}
+
+double usrp1_impl::update_tx_samp_rate(const double samp_rate){
+ boost::mutex::scoped_lock lock = _io_impl->send_handler.get_scoped_lock();
+
+ const size_t rate = uhd::clip<size_t>(
+ boost::math::iround(_master_clock_rate / samp_rate), size_t(std::ceil(_master_clock_rate / 8e6)), 256
+ );
+
+ bool s = this->disable_tx();
+ _iface->poke32(FR_INTERP_RATE, rate/2 - 1);
+ this->restore_tx(s);
+
+ _io_impl->send_handler.set_samp_rate(_master_clock_rate / rate);
+ return _master_clock_rate / rate;
+}
+
+double usrp1_impl::update_rx_dsp_freq(const size_t dspno, const double freq_){
+
+ //correct for outside of rate (wrap around)
+ double freq = std::fmod(freq_, _master_clock_rate);
+ if (std::abs(freq) > _master_clock_rate/2.0)
+ freq -= boost::math::sign(freq)*_master_clock_rate;
+
+ //calculate the freq register word (signed)
+ UHD_ASSERT_THROW(std::abs(freq) <= _master_clock_rate/2.0);
+ static const double scale_factor = std::pow(2.0, 32);
+ const boost::int32_t freq_word = boost::int32_t(boost::math::round((freq / _master_clock_rate) * scale_factor));
+
+ static const boost::uint32_t dsp_index_to_reg_val[4] = {
+ FR_RX_FREQ_0, FR_RX_FREQ_1, FR_RX_FREQ_2, FR_RX_FREQ_3
+ };
+ _iface->poke32(dsp_index_to_reg_val[dspno], ~freq_word + 1);
+
+ return (double(freq_word) / scale_factor) * _master_clock_rate;
+}
+
+double usrp1_impl::update_tx_dsp_freq(const size_t dspno, const double freq){
+ //map the freq shift key to a subdev spec to a particular codec chip
+ _dbc[_tx_subdev_spec.at(dspno).db_name].codec->set_duc_freq(freq, _master_clock_rate);
+ return freq; //assume infinite precision
+}
+
+/***********************************************************************
+ * Async Data
+ **********************************************************************/
+bool usrp1_impl::recv_async_msg(
+ async_metadata_t &async_metadata, double timeout
+){
+ boost::this_thread::disable_interruption di; //disable because the wait can throw
+ return _soft_time_ctrl->get_async_queue().pop_with_timed_wait(async_metadata, timeout);
+}
+
/***********************************************************************
* Data send + helper functions
**********************************************************************/
@@ -292,29 +458,23 @@ size_t usrp1_impl::send(
){
if (_soft_time_ctrl->send_pre(metadata, timeout)) return 0;
+ this->tx_stream_on_off(true); //always enable (it will do the right thing)
size_t num_samps_sent = _io_impl->send_handler.send(
buffs, nsamps_per_buff,
metadata, io_type,
send_mode, timeout
);
- //handle eob flag (commit the buffer, disable the DACs)
+ //handle eob flag (commit the buffer, /*disable the DACs*/)
//check num samps sent to avoid flush on incomplete/timeout
if (metadata.end_of_burst and num_samps_sent == nsamps_per_buff){
- _io_impl->flush_send_buff();
- }
-
- //handle the polling for underflow conditions
- _io_impl->underflow_poll_samp_count += num_samps_sent;
- if (_io_impl->underflow_poll_samp_count >= _tx_samps_per_poll_interval){
- _io_impl->underflow_poll_samp_count = 0; //reset count
- boost::uint8_t underflow = 0;
- ssize_t ret = _ctrl_transport->usrp_control_read(
- VRQ_GET_STATUS, 0, GS_TX_UNDERRUN,
- &underflow, sizeof(underflow)
- );
- if (ret < 0) UHD_MSG(error) << "USRP: underflow check failed" << std::endl;
- else if (underflow) UHD_MSG(fastpath) << "U";
+ async_metadata_t metadata;
+ metadata.channel = 0;
+ metadata.has_time_spec = true;
+ metadata.time_spec = _soft_time_ctrl->get_time();
+ metadata.event_code = async_metadata_t::EVENT_CODE_BURST_ACK;
+ _soft_time_ctrl->get_async_queue().push_with_pop_on_full(metadata);
+ this->tx_stream_on_off(false);
}
return num_samps_sent;
@@ -335,26 +495,14 @@ size_t usrp1_impl::recv(
rx_metadata_t &metadata, const io_type_t &io_type,
recv_mode_t recv_mode, double timeout
){
+ //interleave a "soft" inline message into the receive stream:
+ if (_soft_time_ctrl->get_inline_queue().pop_with_haste(metadata)) return 0;
+
size_t num_samps_recvd = _io_impl->recv_handler.recv(
buffs, nsamps_per_buff,
metadata, io_type,
recv_mode, timeout
);
- _soft_time_ctrl->recv_post(metadata, num_samps_recvd);
-
- //handle the polling for overflow conditions
- _io_impl->overflow_poll_samp_count += num_samps_recvd;
- if (_io_impl->overflow_poll_samp_count >= _rx_samps_per_poll_interval){
- _io_impl->overflow_poll_samp_count = 0; //reset count
- boost::uint8_t overflow = 0;
- ssize_t ret = _ctrl_transport->usrp_control_read(
- VRQ_GET_STATUS, 0, GS_RX_OVERRUN,
- &overflow, sizeof(overflow)
- );
- if (ret < 0) UHD_MSG(error) << "USRP: overflow check failed" << std::endl;
- else if (overflow) UHD_MSG(fastpath) << "O";
- }
-
- return num_samps_recvd;
+ return _soft_time_ctrl->recv_post(metadata, num_samps_recvd);
}
diff --git a/host/lib/usrp/usrp1/mboard_impl.cpp b/host/lib/usrp/usrp1/mboard_impl.cpp
deleted file mode 100644
index a265a5089..000000000
--- a/host/lib/usrp/usrp1/mboard_impl.cpp
+++ /dev/null
@@ -1,407 +0,0 @@
-//
-// Copyright 2010-2011 Ettus Research LLC
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// 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 "usrp1_impl.hpp"
-#include "usrp_commands.h"
-#include "fpga_regs_standard.h"
-#include "fpga_regs_common.h"
-#include "usrp_i2c_addr.h"
-#include <uhd/utils/msg.hpp>
-#include <uhd/utils/log.hpp>
-#include <uhd/usrp/misc_utils.hpp>
-#include <uhd/usrp/mboard_props.hpp>
-#include <uhd/usrp/dboard_props.hpp>
-#include <uhd/usrp/subdev_props.hpp>
-#include <uhd/utils/msg.hpp>
-#include <uhd/utils/assert_has.hpp>
-#include <uhd/utils/images.hpp>
-#include <boost/assign/list_of.hpp>
-#include <boost/foreach.hpp>
-#include <boost/bind.hpp>
-#include <boost/thread/thread.hpp>
-
-using namespace uhd;
-using namespace uhd::usrp;
-
-/***********************************************************************
- * Calculate the RX mux value:
- * The I and Q mux values are intentionally reversed to flip I and Q
- * to account for the reversal in the type conversion routines.
- **********************************************************************/
-static int calc_rx_mux_pair(int adc_for_i, int adc_for_q){
- return (adc_for_i << 2) | (adc_for_q << 0); //shift reversal here
-}
-
-/*!
- * 3 2 1 0
- * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
- * +-----------------------+-------+-------+-------+-------+-+-----+
- * | must be zero | Q3| I3| Q2| I2| Q1| I1| Q0| I0|Z| NCH |
- * +-----------------------+-------+-------+-------+-------+-+-----+
- */
-static boost::uint32_t calc_rx_mux(
- const subdev_spec_t &subdev_spec, wax::obj mboard
-){
- //create look-up-table for mapping dboard name and connection type to ADC flags
- static const int ADC0 = 0, ADC1 = 1, ADC2 = 2, ADC3 = 3;
- static const uhd::dict<std::string, uhd::dict<subdev_conn_t, int> > name_to_conn_to_flag = boost::assign::map_list_of
- ("A", boost::assign::map_list_of
- (SUBDEV_CONN_COMPLEX_IQ, calc_rx_mux_pair(ADC0, ADC1)) //I and Q
- (SUBDEV_CONN_COMPLEX_QI, calc_rx_mux_pair(ADC1, ADC0)) //I and Q
- (SUBDEV_CONN_REAL_I, calc_rx_mux_pair(ADC0, ADC0)) //I and Q (Q identical but ignored Z=1)
- (SUBDEV_CONN_REAL_Q, calc_rx_mux_pair(ADC1, ADC1)) //I and Q (Q identical but ignored Z=1)
- )
- ("B", boost::assign::map_list_of
- (SUBDEV_CONN_COMPLEX_IQ, calc_rx_mux_pair(ADC2, ADC3)) //I and Q
- (SUBDEV_CONN_COMPLEX_QI, calc_rx_mux_pair(ADC3, ADC2)) //I and Q
- (SUBDEV_CONN_REAL_I, calc_rx_mux_pair(ADC2, ADC2)) //I and Q (Q identical but ignored Z=1)
- (SUBDEV_CONN_REAL_Q, calc_rx_mux_pair(ADC3, ADC3)) //I and Q (Q identical but ignored Z=1)
- )
- ;
-
- //extract the number of channels
- size_t nchan = subdev_spec.size();
-
- //calculate the channel flags
- int channel_flags = 0;
- size_t num_reals = 0, num_quads = 0;
- BOOST_FOREACH(const subdev_spec_pair_t &pair, uhd::reversed(subdev_spec)){
- wax::obj dboard = mboard[named_prop_t(MBOARD_PROP_RX_DBOARD, pair.db_name)];
- wax::obj subdev = dboard[named_prop_t(DBOARD_PROP_SUBDEV, pair.sd_name)];
- subdev_conn_t conn = subdev[SUBDEV_PROP_CONNECTION].as<subdev_conn_t>();
- switch(conn){
- case SUBDEV_CONN_COMPLEX_IQ:
- case SUBDEV_CONN_COMPLEX_QI: num_quads++; break;
- case SUBDEV_CONN_REAL_I:
- case SUBDEV_CONN_REAL_Q: num_reals++; break;
- }
- channel_flags = (channel_flags << 4) | name_to_conn_to_flag[pair.db_name][conn];
- }
-
- //calculate Z:
- // for all real sources: Z = 1
- // for all quadrature sources: Z = 0
- // for mixed sources: warning + Z = 0
- int Z = (num_quads > 0)? 0 : 1;
- if (num_quads != 0 and num_reals != 0) UHD_MSG(warning) << boost::format(
- "Mixing real and quadrature rx subdevices is not supported.\n"
- "The Q input to the real source(s) will be non-zero.\n"
- );
-
- //calculate the rx mux value
- return ((channel_flags & 0xffff) << 4) | ((Z & 0x1) << 3) | ((nchan & 0x7) << 0);
-}
-
-/***********************************************************************
- * Calculate the TX mux value:
- * The I and Q mux values are intentionally reversed to flip I and Q
- * to account for the reversal in the type conversion routines.
- **********************************************************************/
-static int calc_tx_mux_pair(int chn_for_i, int chn_for_q){
- return (chn_for_i << 4) | (chn_for_q << 0); //shift reversal here
-}
-
-/*!
- * 3 2 1 0
- * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
- * +-----------------------+-------+-------+-------+-------+-+-----+
- * | | DAC1Q | DAC1I | DAC0Q | DAC0I |0| NCH |
- * +-----------------------------------------------+-------+-+-----+
- */
-static boost::uint32_t calc_tx_mux(
- const subdev_spec_t &subdev_spec, wax::obj mboard
-){
- //create look-up-table for mapping channel number and connection type to flags
- static const int ENB = 1 << 3, CHAN_I0 = 0, CHAN_Q0 = 1, CHAN_I1 = 2, CHAN_Q1 = 3;
- static const uhd::dict<size_t, uhd::dict<subdev_conn_t, int> > chan_to_conn_to_flag = boost::assign::map_list_of
- (0, boost::assign::map_list_of
- (SUBDEV_CONN_COMPLEX_IQ, calc_tx_mux_pair(CHAN_I0 | ENB, CHAN_Q0 | ENB))
- (SUBDEV_CONN_COMPLEX_QI, calc_tx_mux_pair(CHAN_Q0 | ENB, CHAN_I0 | ENB))
- (SUBDEV_CONN_REAL_I, calc_tx_mux_pair(CHAN_I0 | ENB, 0 ))
- (SUBDEV_CONN_REAL_Q, calc_tx_mux_pair(0, CHAN_I0 | ENB))
- )
- (1, boost::assign::map_list_of
- (SUBDEV_CONN_COMPLEX_IQ, calc_tx_mux_pair(CHAN_I1 | ENB, CHAN_Q1 | ENB))
- (SUBDEV_CONN_COMPLEX_QI, calc_tx_mux_pair(CHAN_Q1 | ENB, CHAN_I1 | ENB))
- (SUBDEV_CONN_REAL_I, calc_tx_mux_pair(CHAN_I1 | ENB, 0 ))
- (SUBDEV_CONN_REAL_Q, calc_tx_mux_pair(0, CHAN_I1 | ENB))
- )
- ;
-
- //extract the number of channels
- size_t nchan = subdev_spec.size();
-
- //calculate the channel flags
- int channel_flags = 0, chan = 0;
- uhd::dict<std::string, int> slot_to_chan_count = boost::assign::map_list_of("A", 0)("B", 0);
- BOOST_FOREACH(const subdev_spec_pair_t &pair, subdev_spec){
- wax::obj dboard = mboard[named_prop_t(MBOARD_PROP_TX_DBOARD, pair.db_name)];
- wax::obj subdev = dboard[named_prop_t(DBOARD_PROP_SUBDEV, pair.sd_name)];
- subdev_conn_t conn = subdev[SUBDEV_PROP_CONNECTION].as<subdev_conn_t>();
-
- //combine the channel flags: shift for slot A vs B
- if (pair.db_name == "A") channel_flags |= chan_to_conn_to_flag[chan][conn] << 0;
- if (pair.db_name == "B") channel_flags |= chan_to_conn_to_flag[chan][conn] << 8;
-
- //sanity check, only 1 channel per slot
- slot_to_chan_count[pair.db_name]++;
- if (slot_to_chan_count[pair.db_name] > 1){
- throw uhd::value_error(str(boost::format(
- "dboard slot %s assigned to multiple channels in subdev spec %s"
- ) % pair.db_name % subdev_spec.to_string()));
- }
-
- //increment for the next channel
- chan++;
- }
-
- //calculate the tx mux value
- return ((channel_flags & 0xffff) << 4) | ((nchan & 0x7) << 0);
-}
-
-/*!
- * Capabilities Register
- *
- * 3 2 1 0
- * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
- * +-----------------------------------------------+-+-----+-+-----+
- * | Reserved |T|DUCs |R|DDCs |
- * +-----------------------------------------------+-+-----+-+-----+
- */
-size_t usrp1_impl::get_num_ddcs(void){
- boost::uint32_t regval = _iface->peek32(FR_RB_CAPS);
- return (regval >> 0) & 0x0007;
-}
-
-size_t usrp1_impl::get_num_ducs(void){
- boost::uint32_t regval = _iface->peek32(FR_RB_CAPS);
- return (regval >> 4) & 0x0007;
-}
-
-bool usrp1_impl::has_rx_halfband(void){
- boost::uint32_t regval = _iface->peek32(FR_RB_CAPS);
- return (regval >> 3) & 0x0001;
-}
-
-bool usrp1_impl::has_tx_halfband(void){
- boost::uint32_t regval = _iface->peek32(FR_RB_CAPS);
- return (regval >> 7) & 0x0001;
-}
-
-/***********************************************************************
- * Mboard Initialization
- **********************************************************************/
-void usrp1_impl::mboard_init(void)
-{
- _mboard_proxy = wax_obj_proxy::make(
- boost::bind(&usrp1_impl::mboard_get, this, _1, _2),
- boost::bind(&usrp1_impl::mboard_set, this, _1, _2));
-
- // Normal mode with no loopback or Rx counting
- _iface->poke32(FR_MODE, 0x00000000);
- _iface->poke32(FR_DEBUG_EN, 0x00000000);
- _iface->poke32(FR_RX_SAMPLE_RATE_DIV, 0x00000001); //divide by 2
- _iface->poke32(FR_TX_SAMPLE_RATE_DIV, 0x00000001); //divide by 2
- _iface->poke32(FR_DC_OFFSET_CL_EN, 0x0000000f);
-
- // Reset offset correction registers
- _iface->poke32(FR_ADC_OFFSET_0, 0x00000000);
- _iface->poke32(FR_ADC_OFFSET_1, 0x00000000);
- _iface->poke32(FR_ADC_OFFSET_2, 0x00000000);
- _iface->poke32(FR_ADC_OFFSET_3, 0x00000000);
-
- // Set default for RX format to 16-bit I&Q and no half-band filter bypass
- _iface->poke32(FR_RX_FORMAT, 0x00000300);
-
- // Set default for TX format to 16-bit I&Q
- _iface->poke32(FR_TX_FORMAT, 0x00000000);
-
- UHD_LOG
- << "USRP1 Capabilities" << std::endl
- << " number of duc's: " << get_num_ddcs() << std::endl
- << " number of ddc's: " << get_num_ducs() << std::endl
- << " rx halfband: " << has_rx_halfband() << std::endl
- << " tx halfband: " << has_tx_halfband() << std::endl
- ;
-}
-
-/***********************************************************************
- * Mboard Get
- **********************************************************************/
-static prop_names_t dboard_names = boost::assign::list_of("A")("B");
-
-void usrp1_impl::mboard_get(const wax::obj &key_, wax::obj &val)
-{
- named_prop_t key = named_prop_t::extract(key_);
-
- //handle the get request conditioned on the key
- switch(key.as<mboard_prop_t>()){
- case MBOARD_PROP_NAME:
- val = std::string("usrp1 mboard - " + _iface->mb_eeprom["serial"]);
- return;
-
- case MBOARD_PROP_OTHERS:
- val = prop_names_t();
- return;
-
- case MBOARD_PROP_RX_DBOARD:
- uhd::assert_has(dboard_names, key.name, "dboard name");
- if (key.name == "A") val = _rx_dboard_proxies[DBOARD_SLOT_A]->get_link();
- if (key.name == "B") val = _rx_dboard_proxies[DBOARD_SLOT_B]->get_link();
- return;
-
- case MBOARD_PROP_RX_DBOARD_NAMES:
- val = dboard_names;
- return;
-
- case MBOARD_PROP_TX_DBOARD:
- uhd::assert_has(dboard_names, key.name, "dboard name");
- if (key.name == "A") val = _tx_dboard_proxies[DBOARD_SLOT_A]->get_link();
- if (key.name == "B") val = _tx_dboard_proxies[DBOARD_SLOT_B]->get_link();
- return;
-
- case MBOARD_PROP_TX_DBOARD_NAMES:
- val = dboard_names;
- return;
-
- case MBOARD_PROP_RX_DSP:
- val = _rx_dsp_proxies.get(key.name)->get_link();
- return;
-
- case MBOARD_PROP_RX_DSP_NAMES:
- val = _rx_dsp_proxies.keys();
- return;
-
- case MBOARD_PROP_TX_DSP:
- val = _tx_dsp_proxies.get(key.name)->get_link();
- return;
-
- case MBOARD_PROP_TX_DSP_NAMES:
- val = _tx_dsp_proxies.keys();
- return;
-
- case MBOARD_PROP_CLOCK_CONFIG:
- val = clock_config_t::internal();
- return;
-
- case MBOARD_PROP_RX_SUBDEV_SPEC:
- val = _rx_subdev_spec;
- return;
-
- case MBOARD_PROP_TX_SUBDEV_SPEC:
- val = _tx_subdev_spec;
- return;
-
- case MBOARD_PROP_EEPROM_MAP:
- val = _iface->mb_eeprom;
- return;
-
- case MBOARD_PROP_TIME_NOW:
- val = _soft_time_ctrl->get_time();
- return;
-
- case MBOARD_PROP_CLOCK_RATE:
- val = _clock_ctrl->get_master_clock_freq();
- return;
-
- default: UHD_THROW_PROP_GET_ERROR();
- }
-}
-
-/***********************************************************************
- * Mboard Set
- **********************************************************************/
-void usrp1_impl::mboard_set(const wax::obj &key, const wax::obj &val)
-{
- if(key.type() == typeid(std::string)) {
- if(key.as<std::string>() == "load_eeprom") {
- std::string usrp1_eeprom_image = val.as<std::string>();
- UHD_MSG(status) << "USRP1 EEPROM image: " << usrp1_eeprom_image << std::endl;
- _ctrl_transport->usrp_load_eeprom(val.as<std::string>());
- }
- return;
- }
-
- //handle the get request conditioned on the key
- switch(key.as<mboard_prop_t>()){
-
- case MBOARD_PROP_RX_SUBDEV_SPEC:{
- _rx_subdev_spec = val.as<subdev_spec_t>();
- if (_rx_subdev_spec.size() > this->get_num_ddcs()){
- throw uhd::value_error(str(boost::format(
- "USRP1 suports up to %u RX channels.\n"
- "However, this RX subdev spec requires %u channels\n"
- ) % this->get_num_ddcs() % _rx_subdev_spec.size()));
- }
- verify_rx_subdev_spec(_rx_subdev_spec, _mboard_proxy->get_link());
- //set the mux and set the number of rx channels
- bool s = this->disable_rx();
- _iface->poke32(FR_RX_MUX, calc_rx_mux(_rx_subdev_spec, _mboard_proxy->get_link()));
- this->restore_rx(s);
- this->update_xport_channel_mapping();
- }return;
-
- case MBOARD_PROP_TX_SUBDEV_SPEC:{
- _tx_subdev_spec = val.as<subdev_spec_t>();
- if (_tx_subdev_spec.size() > this->get_num_ducs()){
- throw uhd::value_error(str(boost::format(
- "USRP1 suports up to %u TX channels.\n"
- "However, this TX subdev spec requires %u channels\n"
- ) % this->get_num_ducs() % _tx_subdev_spec.size()));
- }
- verify_tx_subdev_spec(_tx_subdev_spec, _mboard_proxy->get_link());
- //set the mux and set the number of tx channels
- bool s = this->disable_tx();
- _iface->poke32(FR_TX_MUX, calc_tx_mux(_tx_subdev_spec, _mboard_proxy->get_link()));
- this->restore_tx(s);
- this->update_xport_channel_mapping();
- }return;
-
- case MBOARD_PROP_EEPROM_MAP:
- // Step1: commit the map, writing only those values set.
- // Step2: readback the entire eeprom map into the iface.
- val.as<mboard_eeprom_t>().commit(*_iface, mboard_eeprom_t::MAP_B000);
- _iface->mb_eeprom = mboard_eeprom_t(*_iface, mboard_eeprom_t::MAP_B000);
- return;
-
- case MBOARD_PROP_TIME_NOW:
- _soft_time_ctrl->set_time(val.as<time_spec_t>());
- return;
-
- case MBOARD_PROP_CLOCK_RATE:
- UHD_MSG(warning)
- << "I see that you are setting the master clock rate from the API.\n"
- << "You may find it more convenient to burn this setting into the EEPROM.\n"
- << "See the application notes for USRP1 for further instructions.\n"
- ;
- _clock_ctrl->set_master_clock_freq(val.as<double>());
- this->update_xport_channel_mapping();
- return;
-
- case MBOARD_PROP_CLOCK_CONFIG:{
- clock_config_t clock_config = val.as<clock_config_t>();
- if (clock_config.ref_source != clock_config_t::REF_INT){
- throw uhd::value_error("USRP1 clock config: reference source must be set to internal");
- }
- if (clock_config.pps_source != clock_config_t::PPS_INT){
- throw uhd::value_error("USRP1 clock config: PPS source must be set to internal");
- }
- }return;
-
- default: UHD_THROW_PROP_SET_ERROR();
- }
-}
diff --git a/host/lib/usrp/usrp1/soft_time_ctrl.cpp b/host/lib/usrp/usrp1/soft_time_ctrl.cpp
index 1bab34e7b..78481c3ff 100644
--- a/host/lib/usrp/usrp1/soft_time_ctrl.cpp
+++ b/host/lib/usrp/usrp1/soft_time_ctrl.cpp
@@ -16,10 +16,8 @@
//
#include "soft_time_ctrl.hpp"
-#include <uhd/transport/bounded_buffer.hpp>
-#include <boost/any.hpp>
-#include <boost/thread/thread.hpp>
-#include <boost/thread/barrier.hpp>
+#include <uhd/utils/tasks.hpp>
+#include <boost/make_shared.hpp>
#include <boost/thread/condition_variable.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <iostream>
@@ -41,24 +39,17 @@ public:
_nsamps_remaining(0),
_stream_mode(stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS),
_cmd_queue(2),
+ _async_msg_queue(100),
+ _inline_msg_queue(100),
_stream_on_off(stream_on_off)
{
//synchronously spawn a new thread
- boost::barrier spawn_barrier(2);
- _thread_group.create_thread(boost::bind(
- &soft_time_ctrl_impl::recv_cmd_dispatcher, this, boost::ref(spawn_barrier))
- );
- spawn_barrier.wait();
+ _recv_cmd_task = task::make(boost::bind(&soft_time_ctrl_impl::recv_cmd_task, this));
//initialize the time to something
this->set_time(time_spec_t(0.0));
}
- ~soft_time_ctrl_impl(void){
- _thread_group.interrupt_all();
- _thread_group.join_all();
- }
-
/*******************************************************************
* Time control
******************************************************************/
@@ -89,32 +80,47 @@ public:
/*******************************************************************
* Receive control
******************************************************************/
- void recv_post(rx_metadata_t &md, size_t &nsamps){
+ size_t recv_post(rx_metadata_t &md, const size_t nsamps){
boost::mutex::scoped_lock lock(_update_mutex);
+ //Since it timed out on the receive, check for inline messages...
+ //Must do a post check because recv() will not wake up for a message.
+ if (md.error_code == rx_metadata_t::ERROR_CODE_TIMEOUT){
+ if (_inline_msg_queue.pop_with_haste(md)) return 0;
+ }
+
//load the metadata with the expected time
md.has_time_spec = true;
md.time_spec = time_now();
//none of the stuff below matters in continuous streaming mode
- if (_stream_mode == stream_cmd_t::STREAM_MODE_START_CONTINUOUS) return;
+ if (_stream_mode == stream_cmd_t::STREAM_MODE_START_CONTINUOUS) return nsamps;
//When to stop streaming:
//The samples have been received and the stream mode is non-continuous.
//Rewrite the sample count to clip to the requested number of samples.
- if (_nsamps_remaining <= nsamps){
- nsamps = _nsamps_remaining; //set nsamps, then stop
+ if (_nsamps_remaining <= nsamps) switch(_stream_mode){
+ case stream_cmd_t::STREAM_MODE_NUM_SAMPS_AND_MORE:{
+ rx_metadata_t metadata;
+ metadata.has_time_spec = true;
+ metadata.time_spec = this->time_now();
+ metadata.error_code = rx_metadata_t::ERROR_CODE_BROKEN_CHAIN;
+ _inline_msg_queue.push_with_pop_on_full(metadata);
+ } //continue to next case...
+ case stream_cmd_t::STREAM_MODE_NUM_SAMPS_AND_DONE:
md.end_of_burst = true;
- stream_on_off(false);
- return;
+ this->issue_stream_cmd(stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS);
+ return _nsamps_remaining;
+ default: break;
}
//update the consumed samples
_nsamps_remaining -= nsamps;
+ return nsamps;
}
void issue_stream_cmd(const stream_cmd_t &cmd){
- _cmd_queue.push_with_wait(cmd);
+ _cmd_queue.push_with_wait(boost::make_shared<stream_cmd_t>(cmd));
}
void stream_on_off(bool enb){
@@ -134,7 +140,12 @@ public:
//handle late packets
if (time_at < time_now()){
- //TODO post async message
+ async_metadata_t metadata;
+ metadata.channel = 0;
+ metadata.has_time_spec = true;
+ metadata.time_spec = this->time_now();
+ metadata.event_code = async_metadata_t::EVENT_CODE_TIME_ERROR;
+ _async_msg_queue.push_with_pop_on_full(metadata);
return true;
}
@@ -153,7 +164,13 @@ public:
if (not cmd.stream_now){
time_spec_t time_at(cmd.time_spec - TWIDDLE);
if (time_at < time_now()){
- //TODO inject late cmd inline error
+ rx_metadata_t metadata;
+ metadata.has_time_spec = true;
+ metadata.time_spec = this->time_now();
+ metadata.error_code = rx_metadata_t::ERROR_CODE_LATE_COMMAND;
+ _inline_msg_queue.push_with_pop_on_full(metadata);
+ this->issue_stream_cmd(stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS);
+ return;
}
else{
sleep_until_time(lock, time_at);
@@ -177,15 +194,18 @@ public:
_stream_mode = cmd.stream_mode;
}
- void recv_cmd_dispatcher(boost::barrier &spawn_barrier){
- spawn_barrier.wait();
- try{
- boost::any cmd;
- while (true){
- _cmd_queue.pop_with_wait(cmd);
- recv_cmd_handle_cmd(boost::any_cast<stream_cmd_t>(cmd));
- }
- } catch(const boost::thread_interrupted &){}
+ void recv_cmd_task(void){ //task is looped
+ boost::shared_ptr<stream_cmd_t> cmd;
+ _cmd_queue.pop_with_wait(cmd);
+ recv_cmd_handle_cmd(*cmd);
+ }
+
+ bounded_buffer<async_metadata_t> &get_async_queue(void){
+ return _async_msg_queue;
+ }
+
+ bounded_buffer<rx_metadata_t> &get_inline_queue(void){
+ return _inline_msg_queue;
}
private:
@@ -193,9 +213,11 @@ private:
size_t _nsamps_remaining;
stream_cmd_t::stream_mode_t _stream_mode;
time_spec_t _time_offset;
- bounded_buffer<boost::any> _cmd_queue;
+ bounded_buffer<boost::shared_ptr<stream_cmd_t> > _cmd_queue;
+ bounded_buffer<async_metadata_t> _async_msg_queue;
+ bounded_buffer<rx_metadata_t> _inline_msg_queue;
const cb_fcn_type _stream_on_off;
- boost::thread_group _thread_group;
+ task::sptr _recv_cmd_task;
};
/***********************************************************************
diff --git a/host/lib/usrp/usrp1/soft_time_ctrl.hpp b/host/lib/usrp/usrp1/soft_time_ctrl.hpp
index 7fdac7fc8..e91aaf6a2 100644
--- a/host/lib/usrp/usrp1/soft_time_ctrl.hpp
+++ b/host/lib/usrp/usrp1/soft_time_ctrl.hpp
@@ -21,6 +21,7 @@
#include <uhd/types/stream_cmd.hpp>
#include <uhd/types/time_spec.hpp>
#include <uhd/types/metadata.hpp>
+#include <uhd/transport/bounded_buffer.hpp>
#include <boost/utility.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/function.hpp>
@@ -45,8 +46,6 @@ public:
* \return a new soft time control object
*/
static sptr make(const cb_fcn_type &stream_on_off);
- //TODO pass in the error queue for async msgs
- //TODO pass in the queue for inline msgs
//! Set the current time
virtual void set_time(const time_spec_t &time) = 0;
@@ -55,13 +54,19 @@ public:
virtual time_spec_t get_time(void) = 0;
//! Call after the internal recv function
- virtual void recv_post(rx_metadata_t &md, size_t &nsamps) = 0;
+ virtual size_t recv_post(rx_metadata_t &md, const size_t nsamps) = 0;
//! Call before the internal send function
virtual bool send_pre(const tx_metadata_t &md, double &timeout) = 0;
//! Issue a stream command to receive
virtual void issue_stream_cmd(const stream_cmd_t &cmd) = 0;
+
+ //! Get access to a buffer of async metadata
+ virtual transport::bounded_buffer<async_metadata_t> &get_async_queue(void) = 0;
+
+ //! Get access to a buffer of inline metadata
+ virtual transport::bounded_buffer<rx_metadata_t> &get_inline_queue(void) = 0;
};
}} //namespace
diff --git a/host/lib/usrp/usrp1/usrp1_calc_mux.hpp b/host/lib/usrp/usrp1/usrp1_calc_mux.hpp
new file mode 100644
index 000000000..31c190db0
--- /dev/null
+++ b/host/lib/usrp/usrp1/usrp1_calc_mux.hpp
@@ -0,0 +1,156 @@
+//
+// Copyright 2010-2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// 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/config.hpp>
+#include <uhd/exception.hpp>
+#include <uhd/types/dict.hpp>
+#include <uhd/utils/algorithm.hpp>
+#include <boost/assign/list_of.hpp>
+#include <boost/format.hpp>
+#include <utility>
+#include <vector>
+#include <string>
+
+#ifndef INCLUDED_USRP1_CALC_MUX_HPP
+#define INCLUDED_USRP1_CALC_MUX_HPP
+
+//db_name, conn_type for the mux calculations below...
+typedef std::pair<std::string, std::string> mapping_pair_t;
+
+/***********************************************************************
+ * Calculate the RX mux value:
+ * The I and Q mux values are intentionally reversed to flip I and Q
+ * to account for the reversal in the type conversion routines.
+ **********************************************************************/
+static int calc_rx_mux_pair(int adc_for_i, int adc_for_q){
+ return (adc_for_i << 2) | (adc_for_q << 0); //shift reversal here
+}
+
+/*!
+ * 3 2 1 0
+ * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+ * +-----------------------+-------+-------+-------+-------+-+-----+
+ * | must be zero | Q3| I3| Q2| I2| Q1| I1| Q0| I0|Z| NCH |
+ * +-----------------------+-------+-------+-------+-------+-+-----+
+ */
+static boost::uint32_t calc_rx_mux(const std::vector<mapping_pair_t> &mapping){
+ //create look-up-table for mapping dboard name and connection type to ADC flags
+ static const int ADC0 = 0, ADC1 = 1, ADC2 = 2, ADC3 = 3;
+ static const uhd::dict<std::string, uhd::dict<std::string, int> > name_to_conn_to_flag = boost::assign::map_list_of
+ ("A", boost::assign::map_list_of
+ ("IQ", calc_rx_mux_pair(ADC0, ADC1)) //I and Q
+ ("QI", calc_rx_mux_pair(ADC1, ADC0)) //I and Q
+ ("I", calc_rx_mux_pair(ADC0, ADC0)) //I and Q (Q identical but ignored Z=1)
+ ("Q", calc_rx_mux_pair(ADC1, ADC1)) //I and Q (Q identical but ignored Z=1)
+ )
+ ("B", boost::assign::map_list_of
+ ("IQ", calc_rx_mux_pair(ADC2, ADC3)) //I and Q
+ ("QI", calc_rx_mux_pair(ADC3, ADC2)) //I and Q
+ ("I", calc_rx_mux_pair(ADC2, ADC2)) //I and Q (Q identical but ignored Z=1)
+ ("Q", calc_rx_mux_pair(ADC3, ADC3)) //I and Q (Q identical but ignored Z=1)
+ )
+ ;
+
+ //extract the number of channels
+ const size_t nchan = mapping.size();
+
+ //calculate the channel flags
+ int channel_flags = 0;
+ size_t num_reals = 0, num_quads = 0;
+ BOOST_FOREACH(const mapping_pair_t &pair, uhd::reversed(mapping)){
+ const std::string name = pair.first, conn = pair.second;
+ if (conn == "IQ" or conn == "QI") num_quads++;
+ if (conn == "I" or conn == "Q") num_reals++;
+ channel_flags = (channel_flags << 4) | name_to_conn_to_flag[name][conn];
+ }
+
+ //calculate Z:
+ // for all real sources: Z = 1
+ // for all quadrature sources: Z = 0
+ // for mixed sources: warning + Z = 0
+ int Z = (num_quads > 0)? 0 : 1;
+ if (num_quads != 0 and num_reals != 0) UHD_MSG(warning) << boost::format(
+ "Mixing real and quadrature rx subdevices is not supported.\n"
+ "The Q input to the real source(s) will be non-zero.\n"
+ );
+
+ //calculate the rx mux value
+ return ((channel_flags & 0xffff) << 4) | ((Z & 0x1) << 3) | ((nchan & 0x7) << 0);
+}
+
+/***********************************************************************
+ * Calculate the TX mux value:
+ * The I and Q mux values are intentionally reversed to flip I and Q
+ * to account for the reversal in the type conversion routines.
+ **********************************************************************/
+static int calc_tx_mux_pair(int chn_for_i, int chn_for_q){
+ return (chn_for_i << 4) | (chn_for_q << 0); //shift reversal here
+}
+
+/*!
+ * 3 2 1 0
+ * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+ * +-----------------------+-------+-------+-------+-------+-+-----+
+ * | | DAC1Q | DAC1I | DAC0Q | DAC0I |0| NCH |
+ * +-----------------------------------------------+-------+-+-----+
+ */
+static boost::uint32_t calc_tx_mux(const std::vector<mapping_pair_t> &mapping){
+ //create look-up-table for mapping channel number and connection type to flags
+ static const int ENB = 1 << 3, CHAN_I0 = 0, CHAN_Q0 = 1, CHAN_I1 = 2, CHAN_Q1 = 3;
+ static const uhd::dict<size_t, uhd::dict<std::string, int> > chan_to_conn_to_flag = boost::assign::map_list_of
+ (0, boost::assign::map_list_of
+ ("IQ", calc_tx_mux_pair(CHAN_I0 | ENB, CHAN_Q0 | ENB))
+ ("QI", calc_tx_mux_pair(CHAN_Q0 | ENB, CHAN_I0 | ENB))
+ ("I", calc_tx_mux_pair(CHAN_I0 | ENB, 0 ))
+ ("Q", calc_tx_mux_pair(0, CHAN_I0 | ENB))
+ )
+ (1, boost::assign::map_list_of
+ ("IQ", calc_tx_mux_pair(CHAN_I1 | ENB, CHAN_Q1 | ENB))
+ ("QI", calc_tx_mux_pair(CHAN_Q1 | ENB, CHAN_I1 | ENB))
+ ("I", calc_tx_mux_pair(CHAN_I1 | ENB, 0 ))
+ ("Q", calc_tx_mux_pair(0, CHAN_I1 | ENB))
+ )
+ ;
+
+ //extract the number of channels
+ size_t nchan = mapping.size();
+
+ //calculate the channel flags
+ int channel_flags = 0, chan = 0;
+ uhd::dict<std::string, int> slot_to_chan_count = boost::assign::map_list_of("A", 0)("B", 0);
+ BOOST_FOREACH(const mapping_pair_t &pair, mapping){
+ const std::string name = pair.first, conn = pair.second;
+
+ //combine the channel flags: shift for slot A vs B
+ if (name == "A") channel_flags |= chan_to_conn_to_flag[chan][conn] << 0;
+ if (name == "B") channel_flags |= chan_to_conn_to_flag[chan][conn] << 8;
+
+ //sanity check, only 1 channel per slot
+ slot_to_chan_count[name]++;
+ if (slot_to_chan_count[name] > 1) throw uhd::value_error(
+ "cannot assign dboard slot to multiple channels: " + name
+ );
+
+ //increment for the next channel
+ chan++;
+ }
+
+ //calculate the tx mux value
+ return ((channel_flags & 0xffff) << 4) | ((nchan & 0x7) << 0);
+}
+
+#endif /* INCLUDED_USRP1_CALC_MUX_HPP */
diff --git a/host/lib/usrp/usrp1/usrp1_iface.cpp b/host/lib/usrp/usrp1/usrp1_iface.cpp
index 8877f19db..c790aecb4 100644
--- a/host/lib/usrp/usrp1/usrp1_iface.cpp
+++ b/host/lib/usrp/usrp1/usrp1_iface.cpp
@@ -36,7 +36,6 @@ public:
usrp1_iface_impl(uhd::usrp::fx2_ctrl::sptr ctrl_transport)
{
_ctrl_transport = ctrl_transport;
- mb_eeprom = mboard_eeprom_t(*this, mboard_eeprom_t::MAP_B000);
}
~usrp1_iface_impl(void)
@@ -102,78 +101,16 @@ public:
throw uhd::not_implemented_error("Unhandled command peek16()");
return 0;
}
-
- void write_uart(boost::uint8_t, const std::string &) {
- throw uhd::not_implemented_error("Unhandled command write_uart()");
- }
-
- std::string read_uart(boost::uint8_t) {
- throw uhd::not_implemented_error("Unhandled command read_uart()");
- }
/*******************************************************************
* I2C
******************************************************************/
- static const size_t max_i2c_data_bytes = 64;
-
- //TODO: make this handle EEPROM page sizes. right now you can't write over a 16-byte boundary.
- //to accomplish this you'll have to have addr offset as a separate parameter.
-
- void write_i2c(boost::uint8_t addr, const byte_vector_t &bytes)
- {
- UHD_LOGV(always) << "write_i2c:" << std::endl
- << " addr 0x" << std::hex << int(addr) << std::endl
- << " len " << bytes.size() << std::endl
- ;
- UHD_ASSERT_THROW(bytes.size() < max_i2c_data_bytes);
-
- unsigned char buff[max_i2c_data_bytes];
- std::copy(bytes.begin(), bytes.end(), buff);
-
- int ret = _ctrl_transport->usrp_i2c_write(addr & 0xff,
- buff,
- bytes.size());
-
- // TODO throw and catch i2c failures during eeprom read
- if (ret < 0)
- UHD_LOGV(often) << "USRP: failed i2c write: " << ret << std::endl;
+ void write_i2c(boost::uint8_t addr, const byte_vector_t &bytes){
+ return _ctrl_transport->write_i2c(addr, bytes);
}
- byte_vector_t read_i2c(boost::uint8_t addr, size_t num_bytes)
- {
- UHD_LOGV(always) << "read_i2c:" << std::endl
- << " addr 0x" << std::hex << int(addr) << std::endl
- << " len " << num_bytes << std::endl
- ;
- UHD_ASSERT_THROW(num_bytes < max_i2c_data_bytes);
-
- unsigned char buff[max_i2c_data_bytes];
- int ret = _ctrl_transport->usrp_i2c_read(addr & 0xff,
- buff,
- num_bytes);
-
- // TODO throw and catch i2c failures during eeprom read
- if (ret < 0 or (unsigned)ret < num_bytes) {
- UHD_LOGV(often) << "USRP: failed i2c read: " << ret << std::endl;
- return byte_vector_t(num_bytes, 0xff);
- }
-
- byte_vector_t out_bytes;
- for (size_t i = 0; i < num_bytes; i++)
- out_bytes.push_back(buff[i]);
-
- return out_bytes;
- }
-
- //! overload read_eeprom to handle multi-byte reads
- byte_vector_t read_eeprom(
- boost::uint8_t addr,
- boost::uint8_t offset,
- size_t num_bytes
- ){
- //do a zero byte write to start read cycle
- this->write_i2c(addr, byte_vector_t(1, offset));
- return this->read_i2c(addr, num_bytes); //read all bytes
+ byte_vector_t read_i2c(boost::uint8_t addr, size_t num_bytes){
+ return _ctrl_transport->read_i2c(addr, num_bytes);
}
/*******************************************************************
@@ -255,37 +192,6 @@ public:
}
}
- /*******************************************************************
- * Firmware
- *
- * This call is deprecated.
- ******************************************************************/
- void write_firmware_cmd(boost::uint8_t request,
- boost::uint16_t value,
- boost::uint16_t index,
- unsigned char *buff,
- boost::uint16_t length)
- {
- int ret;
-
- if (request & 0x80) {
- ret = _ctrl_transport->usrp_control_read(request,
- value,
- index,
- buff,
- length);
- }
- else {
- ret = _ctrl_transport->usrp_control_write(request,
- value,
- index,
- buff,
- length);
- }
-
- if (ret < 0) throw uhd::io_error("USRP1: failed firmware command");
- }
-
private:
uhd::usrp::fx2_ctrl::sptr _ctrl_transport;
};
diff --git a/host/lib/usrp/usrp1/usrp1_iface.hpp b/host/lib/usrp/usrp1/usrp1_iface.hpp
index e480c22ea..c1ac34f25 100644
--- a/host/lib/usrp/usrp1/usrp1_iface.hpp
+++ b/host/lib/usrp/usrp1/usrp1_iface.hpp
@@ -18,43 +18,27 @@
#ifndef INCLUDED_USRP1_IFACE_HPP
#define INCLUDED_USRP1_IFACE_HPP
-#include <uhd/usrp/mboard_iface.hpp>
+#include "fx2_ctrl.hpp"
+#include "wb_iface.hpp"
+#include <uhd/types/serial.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/utility.hpp>
-#include "../fx2/fx2_ctrl.hpp"
/*!
* The usrp1 interface class:
* Provides a set of functions to implementation layer.
* Including spi, peek, poke, control...
*/
-class usrp1_iface : public uhd::usrp::mboard_iface, boost::noncopyable{
+class usrp1_iface : public wb_iface, public uhd::i2c_iface, public uhd::spi_iface, boost::noncopyable{
public:
typedef boost::shared_ptr<usrp1_iface> sptr;
- //motherboard eeprom map structure
- uhd::usrp::mboard_eeprom_t mb_eeprom;
-
/*!
* Make a new usrp1 interface with the control transport.
* \param ctrl_transport the usrp controller object
* \return a new usrp1 interface object
*/
static sptr make(uhd::usrp::fx2_ctrl::sptr ctrl_transport);
-
- /*!
- * Perform a general USB firmware OUT operation
- * \param request
- * \param value
- * \param index
- * \param data
- * \return
- */
- virtual void write_firmware_cmd(boost::uint8_t request,
- boost::uint16_t value,
- boost::uint16_t index,
- unsigned char* buff,
- boost::uint16_t length) = 0;
};
#endif /* INCLUDED_USRP1_IFACE_HPP */
diff --git a/host/lib/usrp/usrp1/usrp1_impl.cpp b/host/lib/usrp/usrp1/usrp1_impl.cpp
index a3d502038..f27fc0768 100644
--- a/host/lib/usrp/usrp1/usrp1_impl.cpp
+++ b/host/lib/usrp/usrp1/usrp1_impl.cpp
@@ -16,13 +16,14 @@
//
#include "usrp1_impl.hpp"
-#include "fpga_regs_standard.h"
#include "usrp_spi_defs.h"
+#include "usrp_commands.h"
+#include "fpga_regs_standard.h"
+#include "fpga_regs_common.h"
+#include "usrp_i2c_addr.h"
#include <uhd/utils/log.hpp>
#include <uhd/utils/safe_call.hpp>
#include <uhd/transport/usb_control.hpp>
-#include <uhd/usrp/device_props.hpp>
-#include <uhd/usrp/mboard_props.hpp>
#include <uhd/utils/msg.hpp>
#include <uhd/exception.hpp>
#include <uhd/utils/static.hpp>
@@ -101,10 +102,11 @@ static device_addrs_t usrp1_find(const device_addr_t &hint)
try{control = usb_control::make(handle);}
catch(const uhd::exception &){continue;} //ignore claimed
- usrp1_iface::sptr iface = usrp1_iface::make(fx2_ctrl::make(control));
+ fx2_ctrl::sptr fx2_ctrl = fx2_ctrl::make(control);
+ const mboard_eeprom_t mb_eeprom(*fx2_ctrl, mboard_eeprom_t::MAP_B000);
device_addr_t new_addr;
new_addr["type"] = "usrp1";
- new_addr["name"] = iface->mb_eeprom["name"];
+ new_addr["name"] = mb_eeprom["name"];
new_addr["serial"] = handle->get_serial();
//this is a found usrp1 when the hint serial and name match or blank
if (
@@ -122,6 +124,17 @@ static device_addrs_t usrp1_find(const device_addr_t &hint)
* Make
**********************************************************************/
static device::sptr usrp1_make(const device_addr_t &device_addr){
+ return device::sptr(new usrp1_impl(device_addr));
+}
+
+UHD_STATIC_BLOCK(register_usrp1_device){
+ device::register_device(&usrp1_find, &usrp1_make);
+}
+
+/***********************************************************************
+ * Structors
+ **********************************************************************/
+usrp1_impl::usrp1_impl(const device_addr_t &device_addr){
UHD_MSG(status) << "Opening a USRP1 device..." << std::endl;
//extract the FPGA path for the USRP1
@@ -144,67 +157,232 @@ static device::sptr usrp1_make(const device_addr_t &device_addr){
}
UHD_ASSERT_THROW(handle.get() != NULL); //better be found
- //create control objects and a data transport
- usb_control::sptr ctrl_transport = usb_control::make(handle);
- fx2_ctrl::sptr usrp_ctrl = fx2_ctrl::make(ctrl_transport);
- usrp_ctrl->usrp_load_fpga(usrp1_fpga_image);
- usrp_ctrl->usrp_init();
- usb_zero_copy::sptr data_transport = usb_zero_copy::make(
+ ////////////////////////////////////////////////////////////////////
+ // Create controller objects
+ ////////////////////////////////////////////////////////////////////
+ //usb_control::sptr usb_ctrl = usb_control::make(handle);
+ _fx2_ctrl = fx2_ctrl::make(usb_control::make(handle));
+ _fx2_ctrl->usrp_load_fpga(usrp1_fpga_image);
+ _fx2_ctrl->usrp_init();
+ _data_transport = usb_zero_copy::make(
handle, // identifier
6, // IN endpoint
2, // OUT endpoint
device_addr // param hints
);
-
- //create the usrp1 implementation guts
- return device::sptr(new usrp1_impl(data_transport, usrp_ctrl));
-}
-
-UHD_STATIC_BLOCK(register_usrp1_device){
- device::register_device(&usrp1_find, &usrp1_make);
-}
-
-/***********************************************************************
- * Structors
- **********************************************************************/
-usrp1_impl::usrp1_impl(uhd::transport::usb_zero_copy::sptr data_transport,
- uhd::usrp::fx2_ctrl::sptr ctrl_transport)
- : _data_transport(data_transport), _ctrl_transport(ctrl_transport)
-{
- _iface = usrp1_iface::make(ctrl_transport);
-
- //create clock interface
- _clock_ctrl = usrp1_clock_ctrl::make(_iface);
-
- //create codec interface
- _codec_ctrls[DBOARD_SLOT_A] = usrp1_codec_ctrl::make(
- _iface, _clock_ctrl, SPI_ENABLE_CODEC_A
- );
- _codec_ctrls[DBOARD_SLOT_B] = usrp1_codec_ctrl::make(
- _iface, _clock_ctrl, SPI_ENABLE_CODEC_B
+ _iface = usrp1_iface::make(_fx2_ctrl);
+ _soft_time_ctrl = soft_time_ctrl::make(
+ boost::bind(&usrp1_impl::rx_stream_on_off, this, _1)
);
+ _dbc["A"]; _dbc["B"]; //ensure that keys exist
+
+ // Normal mode with no loopback or Rx counting
+ _iface->poke32(FR_MODE, 0x00000000);
+ _iface->poke32(FR_DEBUG_EN, 0x00000000);
+ _iface->poke32(FR_RX_SAMPLE_RATE_DIV, 0x00000001); //divide by 2
+ _iface->poke32(FR_TX_SAMPLE_RATE_DIV, 0x00000001); //divide by 2
+ _iface->poke32(FR_DC_OFFSET_CL_EN, 0x0000000f);
+
+ // Reset offset correction registers
+ _iface->poke32(FR_ADC_OFFSET_0, 0x00000000);
+ _iface->poke32(FR_ADC_OFFSET_1, 0x00000000);
+ _iface->poke32(FR_ADC_OFFSET_2, 0x00000000);
+ _iface->poke32(FR_ADC_OFFSET_3, 0x00000000);
+
+ // Set default for RX format to 16-bit I&Q and no half-band filter bypass
+ _iface->poke32(FR_RX_FORMAT, 0x00000300);
+
+ // Set default for TX format to 16-bit I&Q
+ _iface->poke32(FR_TX_FORMAT, 0x00000000);
+
+ UHD_LOG
+ << "USRP1 Capabilities" << std::endl
+ << " number of duc's: " << get_num_ddcs() << std::endl
+ << " number of ddc's: " << get_num_ducs() << std::endl
+ << " rx halfband: " << has_rx_halfband() << std::endl
+ << " tx halfband: " << has_tx_halfband() << std::endl
+ ;
+
+ ////////////////////////////////////////////////////////////////////
+ // Initialize the properties tree
+ ////////////////////////////////////////////////////////////////////
+ _tree = property_tree::make();
+ _tree->create<std::string>("/name").set("USRP1 Device");
+ const property_tree::path_type mb_path = "/mboards/0";
+ _tree->create<std::string>(mb_path / "name").set("USRP1 (Classic)");
+ _tree->create<std::string>(mb_path / "load_eeprom")
+ .subscribe(boost::bind(&fx2_ctrl::usrp_load_eeprom, _fx2_ctrl, _1));
+
+ ////////////////////////////////////////////////////////////////////
+ // setup the mboard eeprom
+ ////////////////////////////////////////////////////////////////////
+ const mboard_eeprom_t mb_eeprom(*_fx2_ctrl, mboard_eeprom_t::MAP_B000);
+ _tree->create<mboard_eeprom_t>(mb_path / "eeprom")
+ .set(mb_eeprom)
+ .subscribe(boost::bind(&usrp1_impl::set_mb_eeprom, this, _1));
+
+ ////////////////////////////////////////////////////////////////////
+ // create clock control objects
+ ////////////////////////////////////////////////////////////////////
+ _master_clock_rate = 64e6;
+ try{
+ if (not mb_eeprom["mcr"].empty())
+ _master_clock_rate = boost::lexical_cast<double>(mb_eeprom["mcr"]);
+ }catch(const std::exception &e){
+ UHD_MSG(error) << "Error parsing FPGA clock rate from EEPROM: " << e.what() << std::endl;
+ }
+ UHD_MSG(status) << boost::format("Using FPGA clock rate of %fMHz...") % (_master_clock_rate/1e6) << std::endl;
+ _tree->create<double>(mb_path / "tick_rate").set(_master_clock_rate);
+
+ ////////////////////////////////////////////////////////////////////
+ // create codec control objects
+ ////////////////////////////////////////////////////////////////////
+ BOOST_FOREACH(const std::string &db, _dbc.keys()){
+ _dbc[db].codec = usrp1_codec_ctrl::make(_iface, (db == "A")? SPI_ENABLE_CODEC_A : SPI_ENABLE_CODEC_B);
+ const property_tree::path_type rx_codec_path = mb_path / "rx_codecs" / db;
+ const property_tree::path_type tx_codec_path = mb_path / "tx_codecs" / db;
+ _tree->create<std::string>(rx_codec_path / "name").set("ad9522");
+ _tree->create<meta_range_t>(rx_codec_path / "gains/pga/range").set(usrp1_codec_ctrl::rx_pga_gain_range);
+ _tree->create<double>(rx_codec_path / "gains/pga/value")
+ .coerce(boost::bind(&usrp1_impl::update_rx_codec_gain, this, db, _1));
+ _tree->create<std::string>(tx_codec_path / "name").set("ad9522");
+ _tree->create<meta_range_t>(tx_codec_path / "gains/pga/range").set(usrp1_codec_ctrl::tx_pga_gain_range);
+ _tree->create<double>(tx_codec_path / "gains/pga/value")
+ .subscribe(boost::bind(&usrp1_codec_ctrl::set_tx_pga_gain, _dbc[db].codec, _1))
+ .publish(boost::bind(&usrp1_codec_ctrl::get_tx_pga_gain, _dbc[db].codec));
+ }
- //initialize the codecs
- codec_init();
+ ////////////////////////////////////////////////////////////////////
+ // and do the misc mboard sensors
+ ////////////////////////////////////////////////////////////////////
+ //none for now...
+ _tree->create<int>(mb_path / "sensors"); //phony property so this dir exists
+
+ ////////////////////////////////////////////////////////////////////
+ // create frontend control objects
+ ////////////////////////////////////////////////////////////////////
+ _tree->create<subdev_spec_t>(mb_path / "rx_subdev_spec")
+ .subscribe(boost::bind(&usrp1_impl::update_rx_subdev_spec, this, _1));
+ _tree->create<subdev_spec_t>(mb_path / "tx_subdev_spec")
+ .subscribe(boost::bind(&usrp1_impl::update_tx_subdev_spec, this, _1));
+
+ ////////////////////////////////////////////////////////////////////
+ // create rx dsp control objects
+ ////////////////////////////////////////////////////////////////////
+ for (size_t dspno = 0; dspno < get_num_ddcs(); dspno++){
+ property_tree::path_type rx_dsp_path = mb_path / str(boost::format("rx_dsps/%u") % dspno);
+ _tree->create<double>(rx_dsp_path / "rate/value")
+ .coerce(boost::bind(&usrp1_impl::update_rx_samp_rate, this, _1));
+ _tree->create<double>(rx_dsp_path / "freq/value")
+ .coerce(boost::bind(&usrp1_impl::update_rx_dsp_freq, this, dspno, _1));
+ _tree->create<meta_range_t>(rx_dsp_path / "freq/range")
+ .set(meta_range_t(-_master_clock_rate/2, +_master_clock_rate/2));
+ _tree->create<stream_cmd_t>(rx_dsp_path / "stream_cmd");
+ if (dspno == 0){
+ //only subscribe the callback for dspno 0 since it will stream all dsps
+ _tree->access<stream_cmd_t>(rx_dsp_path / "stream_cmd")
+ .subscribe(boost::bind(&soft_time_ctrl::issue_stream_cmd, _soft_time_ctrl, _1));
+ }
+ }
- //initialize the mboard
- mboard_init();
+ ////////////////////////////////////////////////////////////////////
+ // create tx dsp control objects
+ ////////////////////////////////////////////////////////////////////
+ for (size_t dspno = 0; dspno < get_num_ducs(); dspno++){
+ property_tree::path_type tx_dsp_path = mb_path / str(boost::format("tx_dsps/%u") % dspno);
+ _tree->create<double>(tx_dsp_path / "rate/value")
+ .coerce(boost::bind(&usrp1_impl::update_tx_samp_rate, this, _1));
+ _tree->create<double>(tx_dsp_path / "freq/value")
+ .coerce(boost::bind(&usrp1_impl::update_tx_dsp_freq, this, dspno, _1));
+ _tree->create<meta_range_t>(tx_dsp_path / "freq/range") //magic scalar comes from codec control:
+ .set(meta_range_t(-_master_clock_rate*0.6875, +_master_clock_rate*0.6875));
+ }
- //initialize the dboards
- dboard_init();
+ ////////////////////////////////////////////////////////////////////
+ // create time control objects
+ ////////////////////////////////////////////////////////////////////
+ _tree->create<time_spec_t>(mb_path / "time/now")
+ .publish(boost::bind(&soft_time_ctrl::get_time, _soft_time_ctrl))
+ .subscribe(boost::bind(&soft_time_ctrl::set_time, _soft_time_ctrl, _1));
+
+ _tree->create<std::vector<std::string> >(mb_path / "clock_source/options").set(std::vector<std::string>(1, "internal"));
+ _tree->create<std::vector<std::string> >(mb_path / "time_source/options").set(std::vector<std::string>(1, "none"));
+ _tree->create<std::string>(mb_path / "clock_source/value").set("internal");
+ _tree->create<std::string>(mb_path / "time_source/value").set("none");
+
+ ////////////////////////////////////////////////////////////////////
+ // create dboard control objects
+ ////////////////////////////////////////////////////////////////////
+ BOOST_FOREACH(const std::string &db, _dbc.keys()){
+
+ //read the dboard eeprom to extract the dboard ids
+ dboard_eeprom_t rx_db_eeprom, tx_db_eeprom, gdb_eeprom;
+ rx_db_eeprom.load(*_fx2_ctrl, (db == "A")? (I2C_ADDR_RX_A) : (I2C_ADDR_RX_B));
+ tx_db_eeprom.load(*_fx2_ctrl, (db == "A")? (I2C_ADDR_TX_A) : (I2C_ADDR_TX_B));
+ gdb_eeprom.load(*_fx2_ctrl, (db == "A")? (I2C_ADDR_TX_A ^ 5) : (I2C_ADDR_TX_B ^ 5));
+
+ //create the properties and register subscribers
+ _tree->create<dboard_eeprom_t>(mb_path / "dboards" / db/ "rx_eeprom")
+ .set(rx_db_eeprom)
+ .subscribe(boost::bind(&usrp1_impl::set_db_eeprom, this, db, "rx", _1));
+ _tree->create<dboard_eeprom_t>(mb_path / "dboards" / db/ "tx_eeprom")
+ .set(tx_db_eeprom)
+ .subscribe(boost::bind(&usrp1_impl::set_db_eeprom, this, db, "tx", _1));
+ _tree->create<dboard_eeprom_t>(mb_path / "dboards" / db/ "gdb_eeprom")
+ .set(gdb_eeprom)
+ .subscribe(boost::bind(&usrp1_impl::set_db_eeprom, this, db, "gdb", _1));
+
+ //create a new dboard interface and manager
+ _dbc[db].dboard_iface = make_dboard_iface(
+ _iface, _dbc[db].codec,
+ (db == "A")? DBOARD_SLOT_A : DBOARD_SLOT_B,
+ _master_clock_rate, rx_db_eeprom.id
+ );
+ _tree->create<dboard_iface::sptr>(mb_path / "dboards" / db/ "iface").set(_dbc[db].dboard_iface);
+ _dbc[db].dboard_manager = dboard_manager::make(
+ rx_db_eeprom.id,
+ ((gdb_eeprom.id == dboard_id_t::none())? tx_db_eeprom : gdb_eeprom).id,
+ _dbc[db].dboard_iface
+ );
+ BOOST_FOREACH(const std::string &name, _dbc[db].dboard_manager->get_rx_subdev_names()){
+ dboard_manager::populate_prop_tree_from_subdev(
+ _tree->subtree(mb_path / "dboards" / db/ "rx_frontends" / name),
+ _dbc[db].dboard_manager->get_rx_subdev(name)
+ );
+ }
+ BOOST_FOREACH(const std::string &name, _dbc[db].dboard_manager->get_tx_subdev_names()){
+ dboard_manager::populate_prop_tree_from_subdev(
+ _tree->subtree(mb_path / "dboards" / db/ "tx_frontends" / name),
+ _dbc[db].dboard_manager->get_tx_subdev(name)
+ );
+ }
- //initialize the dsps
- rx_dsp_init();
+ //init the subdev specs if we have a dboard (wont leave this loop empty)
+ if (rx_db_eeprom.id != dboard_id_t::none() or _rx_subdev_spec.empty()){
+ _rx_subdev_spec = subdev_spec_t(db + ":" + _dbc[db].dboard_manager->get_rx_subdev_names()[0]);
+ }
+ if (tx_db_eeprom.id != dboard_id_t::none() or _tx_subdev_spec.empty()){
+ _tx_subdev_spec = subdev_spec_t(db + ":" + _dbc[db].dboard_manager->get_tx_subdev_names()[0]);
+ }
+ }
- //initialize the dsps
- tx_dsp_init();
+ //initialize io handling
+ this->io_init();
- //init the subdev specs
- this->mboard_set(MBOARD_PROP_RX_SUBDEV_SPEC, subdev_spec_t());
- this->mboard_set(MBOARD_PROP_TX_SUBDEV_SPEC, subdev_spec_t());
+ ////////////////////////////////////////////////////////////////////
+ // do some post-init tasks
+ ////////////////////////////////////////////////////////////////////
+ //and now that the tick rate is set, init the host rates to something
+ BOOST_FOREACH(const std::string &name, _tree->list(mb_path / "rx_dsps")){
+ _tree->access<double>(mb_path / "rx_dsps" / name / "rate" / "value").set(1e6);
+ }
+ BOOST_FOREACH(const std::string &name, _tree->list(mb_path / "tx_dsps")){
+ _tree->access<double>(mb_path / "tx_dsps" / name / "rate" / "value").set(1e6);
+ }
- //initialize the send/recv
- io_init();
+ _tree->access<subdev_spec_t>(mb_path / "rx_subdev_spec").set(_rx_subdev_spec);
+ _tree->access<subdev_spec_t>(mb_path / "tx_subdev_spec").set(_tx_subdev_spec);
+
}
usrp1_impl::~usrp1_impl(void){UHD_SAFE_CALL(
@@ -212,42 +390,52 @@ usrp1_impl::~usrp1_impl(void){UHD_SAFE_CALL(
this->enable_tx(false);
)}
-bool usrp1_impl::recv_async_msg(uhd::async_metadata_t &, double timeout){
- //dummy fill-in for the recv_async_msg
- boost::this_thread::sleep(boost::posix_time::microseconds(long(timeout*1e6)));
- return false;
+/*!
+ * Capabilities Register
+ *
+ * 3 2 1 0
+ * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+ * +-----------------------------------------------+-+-----+-+-----+
+ * | Reserved |T|DUCs |R|DDCs |
+ * +-----------------------------------------------+-+-----+-+-----+
+ */
+size_t usrp1_impl::get_num_ddcs(void){
+ boost::uint32_t regval = _iface->peek32(FR_RB_CAPS);
+ return (regval >> 0) & 0x0007;
}
-/***********************************************************************
- * Device Get
- **********************************************************************/
-void usrp1_impl::get(const wax::obj &key_, wax::obj &val)
-{
- named_prop_t key = named_prop_t::extract(key_);
-
- //handle the get request conditioned on the key
- switch(key.as<device_prop_t>()){
- case DEVICE_PROP_NAME:
- val = std::string("usrp1 device");
- return;
-
- case DEVICE_PROP_MBOARD:
- UHD_ASSERT_THROW(key.name == "");
- val = _mboard_proxy->get_link();
- return;
+size_t usrp1_impl::get_num_ducs(void){
+ boost::uint32_t regval = _iface->peek32(FR_RB_CAPS);
+ return (regval >> 4) & 0x0007;
+}
- case DEVICE_PROP_MBOARD_NAMES:
- val = prop_names_t(1, ""); //vector of size 1 with empty string
- return;
+bool usrp1_impl::has_rx_halfband(void){
+ boost::uint32_t regval = _iface->peek32(FR_RB_CAPS);
+ return (regval >> 3) & 0x0001;
+}
- default: UHD_THROW_PROP_GET_ERROR();
- }
+bool usrp1_impl::has_tx_halfband(void){
+ boost::uint32_t regval = _iface->peek32(FR_RB_CAPS);
+ return (regval >> 7) & 0x0001;
}
/***********************************************************************
- * Device Set
+ * Properties callback methods below
**********************************************************************/
-void usrp1_impl::set(const wax::obj &, const wax::obj &)
-{
- UHD_THROW_PROP_SET_ERROR();
+void usrp1_impl::set_mb_eeprom(const uhd::usrp::mboard_eeprom_t &mb_eeprom){
+ mb_eeprom.commit(*_fx2_ctrl, mboard_eeprom_t::MAP_B000);
+}
+
+void usrp1_impl::set_db_eeprom(const std::string &db, const std::string &type, const uhd::usrp::dboard_eeprom_t &db_eeprom){
+ if (type == "rx") db_eeprom.store(*_fx2_ctrl, (db == "A")? (I2C_ADDR_RX_A) : (I2C_ADDR_RX_B));
+ if (type == "tx") db_eeprom.store(*_fx2_ctrl, (db == "A")? (I2C_ADDR_TX_A) : (I2C_ADDR_TX_B));
+ if (type == "gdb") db_eeprom.store(*_fx2_ctrl, (db == "A")? (I2C_ADDR_TX_A ^ 5) : (I2C_ADDR_TX_B ^ 5));
+}
+
+double usrp1_impl::update_rx_codec_gain(const std::string &db, const double gain){
+ //set gain on both I and Q, readback on one
+ //TODO in the future, gains should have individual control
+ _dbc[db].codec->set_rx_pga_gain(gain, 'A');
+ _dbc[db].codec->set_rx_pga_gain(gain, 'B');
+ return _dbc[db].codec->get_rx_pga_gain('A');
}
diff --git a/host/lib/usrp/usrp1/usrp1_impl.hpp b/host/lib/usrp/usrp1/usrp1_impl.hpp
index bea1dbe3b..1fe0c1784 100644
--- a/host/lib/usrp/usrp1/usrp1_impl.hpp
+++ b/host/lib/usrp/usrp1/usrp1_impl.hpp
@@ -16,16 +16,17 @@
//
#include "usrp1_iface.hpp"
-#include "clock_ctrl.hpp"
#include "codec_ctrl.hpp"
#include "soft_time_ctrl.hpp"
#include <uhd/device.hpp>
+#include <uhd/property_tree.hpp>
#include <uhd/utils/pimpl.hpp>
#include <uhd/types/dict.hpp>
#include <uhd/types/otw_type.hpp>
#include <uhd/types/clock_config.hpp>
#include <uhd/types/stream_cmd.hpp>
#include <uhd/usrp/dboard_id.hpp>
+#include <uhd/usrp/mboard_eeprom.hpp>
#include <uhd/usrp/subdev_spec.hpp>
#include <uhd/usrp/dboard_eeprom.hpp>
#include <uhd/usrp/dboard_manager.hpp>
@@ -35,29 +36,6 @@
#define INCLUDED_USRP1_IMPL_HPP
/*!
- * Simple wax obj proxy class:
- * Provides a wax obj interface for a set and a get function.
- * This allows us to create nested properties structures
- * while maintaining flattened code within the implementation.
- */
-class wax_obj_proxy : public wax::obj {
-public:
- typedef boost::function<void(const wax::obj &, wax::obj &)> get_t;
- typedef boost::function<void(const wax::obj &, const wax::obj &)> set_t;
- typedef boost::shared_ptr<wax_obj_proxy> sptr;
-
- static sptr make(const get_t &get, const set_t &set){
- return sptr(new wax_obj_proxy(get, set));
- }
-
-private:
- get_t _get; set_t _set;
- wax_obj_proxy(const get_t &get, const set_t &set): _get(get), _set(set) {};
- void get(const wax::obj &key, wax::obj &val) {return _get(key, val);}
- void set(const wax::obj &key, const wax::obj &val) {return _set(key, val);}
-};
-
-/*!
* USRP1 implementation guts:
* The implementation details are encapsulated here.
* Handles properties on the mboard, dboard, dsps...
@@ -73,9 +51,7 @@ public:
static const std::vector<dboard_slot_t> _dboard_slots;
//structors
- usrp1_impl(uhd::transport::usb_zero_copy::sptr data_transport,
- uhd::usrp::fx2_ctrl::sptr ctrl_transport);
-
+ usrp1_impl(const uhd::device_addr_t &);
~usrp1_impl(void);
//the io interface
@@ -97,125 +73,73 @@ public:
bool recv_async_msg(uhd::async_metadata_t &, double);
private:
- /*!
- * Make a usrp1 dboard interface.
- * \param iface the usrp1 interface object
- * \param clock the clock control interface
- * \param codec the codec control interface
- * \param dboard_slot the slot identifier
- * \param rx_dboard_id the db id for the rx board (used for evil dbsrx purposes)
- * \return a sptr to a new dboard interface
- */
- static uhd::usrp::dboard_iface::sptr make_dboard_iface(
- usrp1_iface::sptr iface,
- usrp1_clock_ctrl::sptr clock,
- usrp1_codec_ctrl::sptr codec,
- dboard_slot_t dboard_slot,
- const uhd::usrp::dboard_id_t &rx_dboard_id
- );
+ uhd::property_tree::sptr _tree;
- //!call when the channel mapping is changed
- void update_xport_channel_mapping(void);
+ //device properties interface
+ void get(const wax::obj &, wax::obj &val){
+ val = _tree; //entry point into property tree
+ }
- //soft time control emulation
+ //controllers
+ uhd::usrp::fx2_ctrl::sptr _fx2_ctrl;
+ usrp1_iface::sptr _iface;
uhd::usrp::soft_time_ctrl::sptr _soft_time_ctrl;
+ uhd::transport::usb_zero_copy::sptr _data_transport;
+ struct db_container_type{
+ usrp1_codec_ctrl::sptr codec;
+ uhd::usrp::dboard_iface::sptr dboard_iface;
+ uhd::usrp::dboard_manager::sptr dboard_manager;
+ };
+ uhd::dict<std::string, db_container_type> _dbc;
- //interface to ioctls and file descriptor
- usrp1_iface::sptr _iface;
+ double _master_clock_rate; //clock rate shadow
+
+ void set_mb_eeprom(const uhd::usrp::mboard_eeprom_t &);
+ void set_db_eeprom(const std::string &, const std::string &, const uhd::usrp::dboard_eeprom_t &);
+ double update_rx_codec_gain(const std::string &, const double); //sets A and B at once
+ void update_rx_subdev_spec(const uhd::usrp::subdev_spec_t &);
+ void update_tx_subdev_spec(const uhd::usrp::subdev_spec_t &);
+ double update_rx_samp_rate(const double);
+ double update_tx_samp_rate(const double);
+ double update_rx_dsp_freq(const size_t, const double);
+ double update_tx_dsp_freq(const size_t, const double);
+
+ static uhd::usrp::dboard_iface::sptr make_dboard_iface(
+ usrp1_iface::sptr,
+ usrp1_codec_ctrl::sptr,
+ dboard_slot_t,
+ const double,
+ const uhd::usrp::dboard_id_t &
+ );
//handle io stuff
UHD_PIMPL_DECL(io_impl) _io_impl;
void io_init(void);
void rx_stream_on_off(bool);
+ void tx_stream_on_off(bool);
void handle_overrun(size_t);
- //underrun and overrun poll intervals
- size_t _rx_samps_per_poll_interval;
- size_t _tx_samps_per_poll_interval;
-
//otw types
- uhd::otw_type_t _rx_otw_type;
- uhd::otw_type_t _tx_otw_type;
-
- //configuration shadows
+ uhd::otw_type_t _rx_otw_type, _tx_otw_type;
uhd::usrp::subdev_spec_t _rx_subdev_spec, _tx_subdev_spec;
- //clock control
- usrp1_clock_ctrl::sptr _clock_ctrl;
-
- //ad9862 codec control interface
- uhd::dict<dboard_slot_t, usrp1_codec_ctrl::sptr> _codec_ctrls;
-
- //codec properties interfaces
- void codec_init(void);
- void rx_codec_get(const wax::obj &, wax::obj &, dboard_slot_t);
- void rx_codec_set(const wax::obj &, const wax::obj &, dboard_slot_t);
- void tx_codec_get(const wax::obj &, wax::obj &, dboard_slot_t);
- void tx_codec_set(const wax::obj &, const wax::obj &, dboard_slot_t);
- uhd::dict<dboard_slot_t, wax_obj_proxy::sptr> _rx_codec_proxies, _tx_codec_proxies;
-
- //device functions and settings
- void get(const wax::obj &, wax::obj &);
- void set(const wax::obj &, const wax::obj &);
-
- //mboard functions and settings
- void mboard_init(void);
- void mboard_get(const wax::obj &, wax::obj &);
- void mboard_set(const wax::obj &, const wax::obj &);
- wax_obj_proxy::sptr _mboard_proxy;
-
- //xx dboard functions and settings
- void dboard_init(void);
- uhd::dict<dboard_slot_t, uhd::usrp::dboard_manager::sptr> _dboard_managers;
- uhd::dict<dboard_slot_t, uhd::usrp::dboard_iface::sptr> _dboard_ifaces;
-
- //rx dboard functions and settings
- uhd::dict<dboard_slot_t, uhd::usrp::dboard_eeprom_t> _rx_db_eeproms;
- void rx_dboard_get(const wax::obj &, wax::obj &, dboard_slot_t);
- void rx_dboard_set(const wax::obj &, const wax::obj &, dboard_slot_t);
- uhd::dict<dboard_slot_t, wax_obj_proxy::sptr> _rx_dboard_proxies;
-
- //tx dboard functions and settings
- uhd::dict<dboard_slot_t, uhd::usrp::dboard_eeprom_t> _tx_db_eeproms, _gdb_eeproms;
- void tx_dboard_get(const wax::obj &, wax::obj &, dboard_slot_t);
- void tx_dboard_set(const wax::obj &, const wax::obj &, dboard_slot_t);
- uhd::dict<dboard_slot_t, wax_obj_proxy::sptr> _tx_dboard_proxies;
-
- //rx dsp functions and settings
- void rx_dsp_init(void);
- void rx_dsp_get(const wax::obj &, wax::obj &, size_t);
- void rx_dsp_set(const wax::obj &, const wax::obj &, size_t);
- uhd::dict<size_t, double> _rx_dsp_freqs;
- size_t _rx_dsp_decim;
- uhd::dict<std::string, wax_obj_proxy::sptr> _rx_dsp_proxies;
-
- //tx dsp functions and settings
- void tx_dsp_init(void);
- void tx_dsp_get(const wax::obj &, wax::obj &, size_t);
- void tx_dsp_set(const wax::obj &, const wax::obj &, size_t);
- uhd::dict<size_t, double> _tx_dsp_freqs;
- size_t _tx_dsp_interp;
- uhd::dict<std::string, wax_obj_proxy::sptr> _tx_dsp_proxies;
-
- //transports
- uhd::transport::usb_zero_copy::sptr _data_transport;
- uhd::usrp::fx2_ctrl::sptr _ctrl_transport;
-
//capabilities
size_t get_num_ducs(void);
size_t get_num_ddcs(void);
bool has_rx_halfband(void);
bool has_tx_halfband(void);
+ void vandal_conquest_loop(void);
+
//handle the enables
bool _rx_enabled, _tx_enabled;
void enable_rx(bool enb){
_rx_enabled = enb;
- _ctrl_transport->usrp_rx_enable(enb);
+ _fx2_ctrl->usrp_rx_enable(enb);
}
void enable_tx(bool enb){
_tx_enabled = enb;
- _ctrl_transport->usrp_tx_enable(enb);
+ _fx2_ctrl->usrp_tx_enable(enb);
}
//conditionally disable and enable rx
diff --git a/host/lib/usrp/usrp2/CMakeLists.txt b/host/lib/usrp/usrp2/CMakeLists.txt
index c3f138c24..10f7407b0 100644
--- a/host/lib/usrp/usrp2/CMakeLists.txt
+++ b/host/lib/usrp/usrp2/CMakeLists.txt
@@ -1,5 +1,5 @@
#
-# Copyright 2010-2011 Ettus Research LLC
+# Copyright 2011 Ettus Research LLC
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -27,19 +27,10 @@ LIBUHD_REGISTER_COMPONENT("USRP2" ENABLE_USRP2 ON "ENABLE_LIBUHD" OFF)
IF(ENABLE_USRP2)
LIBUHD_APPEND_SOURCES(
${CMAKE_CURRENT_SOURCE_DIR}/clock_ctrl.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/clock_ctrl.hpp
${CMAKE_CURRENT_SOURCE_DIR}/codec_ctrl.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/codec_ctrl.hpp
- ${CMAKE_CURRENT_SOURCE_DIR}/codec_impl.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/dboard_impl.cpp
${CMAKE_CURRENT_SOURCE_DIR}/dboard_iface.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/dsp_impl.cpp
${CMAKE_CURRENT_SOURCE_DIR}/io_impl.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/mboard_impl.cpp
${CMAKE_CURRENT_SOURCE_DIR}/usrp2_iface.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/usrp2_iface.hpp
${CMAKE_CURRENT_SOURCE_DIR}/usrp2_impl.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/usrp2_impl.hpp
- ${CMAKE_CURRENT_SOURCE_DIR}/usrp2_regs.hpp
)
ENDIF(ENABLE_USRP2)
diff --git a/host/lib/usrp/usrp2/codec_impl.cpp b/host/lib/usrp/usrp2/codec_impl.cpp
deleted file mode 100644
index 26da42759..000000000
--- a/host/lib/usrp/usrp2/codec_impl.cpp
+++ /dev/null
@@ -1,181 +0,0 @@
-//
-// Copyright 2010-2011 Ettus Research LLC
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// 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/utils/assert_has.hpp>
-#include <uhd/exception.hpp>
-#include <uhd/usrp/codec_props.hpp>
-#include <uhd/types/dict.hpp>
-#include <uhd/types/ranges.hpp>
-#include <boost/bind.hpp>
-#include <boost/assign/list_of.hpp>
-
-using namespace uhd;
-using namespace uhd::usrp;
-using namespace boost::assign;
-
-//this only applies to N2XX
-static const uhd::dict<std::string, gain_range_t> codec_rx_gain_ranges = map_list_of
- ("digital", gain_range_t(0, 6.0, 0.5))
- ("digital-fine", gain_range_t(0, 0.5, 0.05));
-
-
-/***********************************************************************
- * 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)
- );
-
- //initialize gain names. keeps get_rx_gain() from getting a gain
- //that hasn't been set yet.
- BOOST_FOREACH(std::string key, codec_rx_gain_ranges.keys()) {
- _codec_rx_gains[key] = codec_rx_gain_ranges[key].start();
- }
-}
-
-/***********************************************************************
- * RX Codec Properties
- **********************************************************************/
-void usrp2_mboard_impl::rx_codec_get(const wax::obj &key_, wax::obj &val){
- named_prop_t key = named_prop_t::extract(key_);
-
- //handle the get request conditioned on the key
- switch(key.as<codec_prop_t>()){
- case CODEC_PROP_NAME:
- switch(_iface->get_rev()){
- case usrp2_iface::USRP_N200:
- case usrp2_iface::USRP_N210:
- case usrp2_iface::USRP_N200_R4:
- case usrp2_iface::USRP_N210_R4:
- val = _iface->get_cname() + " adc - ads62p44";
- break;
-
- case usrp2_iface::USRP2_REV3:
- case usrp2_iface::USRP2_REV4:
- val = _iface->get_cname() + " adc - ltc2284";
- break;
-
- case usrp2_iface::USRP_NXXX:
- val = _iface->get_cname() + " adc - ??????";
- break;
- }
- return;
-
- case CODEC_PROP_OTHERS:
- val = prop_names_t();
- return;
-
- case CODEC_PROP_GAIN_NAMES:
- switch(_iface->get_rev()){
- case usrp2_iface::USRP_N200:
- case usrp2_iface::USRP_N210:
- val = prop_names_t(codec_rx_gain_ranges.keys());
- return;
-
- default: val = prop_names_t();
- }
- return;
-
- case CODEC_PROP_GAIN_I:
- case CODEC_PROP_GAIN_Q:
- assert_has(_codec_rx_gains.keys(), key.name, "codec rx gain name");
- val = _codec_rx_gains[key.name];
- return;
-
- case CODEC_PROP_GAIN_RANGE:
- assert_has(codec_rx_gain_ranges.keys(), key.name, "codec rx gain range name");
- val = codec_rx_gain_ranges[key.name];
- return;
-
- default: UHD_THROW_PROP_GET_ERROR();
- }
-}
-
-void usrp2_mboard_impl::rx_codec_set(const wax::obj &key_, const wax::obj &val){
- named_prop_t key = named_prop_t::extract(key_);
-
- switch(key.as<codec_prop_t>()) {
- case CODEC_PROP_GAIN_I:
- case CODEC_PROP_GAIN_Q:
- this->rx_codec_set_gain(val.as<double>(), key.name);
- return;
-
- default: UHD_THROW_PROP_SET_ERROR();
- }
-}
-
-/***********************************************************************
- * Helper function to set RX codec gain
- ***********************************************************************/
-
-void usrp2_mboard_impl::rx_codec_set_gain(double gain, const std::string &name){
- assert_has(codec_rx_gain_ranges.keys(), name, "codec rx gain name");
-
- _codec_rx_gains[name] = gain;
-/*
- if(name == "analog") {
- _codec_ctrl->set_rx_analog_gain(gain > 0); //just turn it on or off
- return;
- }
-*/
- if(name == "digital") {
- _codec_ctrl->set_rx_digital_gain(gain);
- return;
- }
- if(name == "digital-fine") {
- _codec_ctrl->set_rx_digital_fine_gain(gain);
- return;
- }
- UHD_THROW_PROP_SET_ERROR();
-}
-
-
-/***********************************************************************
- * TX Codec Properties
- **********************************************************************/
-void usrp2_mboard_impl::tx_codec_get(const wax::obj &key_, wax::obj &val){
- named_prop_t key = named_prop_t::extract(key_);
-
- //handle the get request conditioned on the key
- switch(key.as<codec_prop_t>()){
- case CODEC_PROP_NAME:
- val = _iface->get_cname() + " 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_impl.cpp b/host/lib/usrp/usrp2/dboard_impl.cpp
deleted file mode 100644
index 8c6379d66..000000000
--- a/host/lib/usrp/usrp2/dboard_impl.cpp
+++ /dev/null
@@ -1,183 +0,0 @@
-//
-// Copyright 2010-2011 Ettus Research LLC
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// 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 "usrp2_regs.hpp"
-#include "fw_common.h"
-#include <uhd/usrp/misc_utils.hpp>
-#include <uhd/usrp/dsp_utils.hpp>
-#include <uhd/usrp/subdev_props.hpp>
-#include <uhd/usrp/dboard_props.hpp>
-#include <uhd/exception.hpp>
-#include <boost/format.hpp>
-#include <boost/bind.hpp>
-#include <boost/asio.hpp> //htonl and ntohl
-#include <iostream>
-
-using namespace uhd;
-using namespace uhd::usrp;
-
-/***********************************************************************
- * Helper Methods
- **********************************************************************/
-void usrp2_mboard_impl::dboard_init(void){
- //read the dboard eeprom to extract the dboard ids
- _rx_db_eeprom.load(*_iface, USRP2_I2C_ADDR_RX_DB);
- _tx_db_eeprom.load(*_iface, USRP2_I2C_ADDR_TX_DB);
- _gdb_eeprom.load(*_iface, USRP2_I2C_ADDR_TX_DB ^ 5);
-
- //create a new dboard interface and manager
- _dboard_iface = make_usrp2_dboard_iface(_iface, _clock_ctrl);
- _dboard_manager = dboard_manager::make(
- _rx_db_eeprom.id,
- ((_gdb_eeprom.id == dboard_id_t::none())? _tx_db_eeprom : _gdb_eeprom).id,
- _dboard_iface
- );
-
- //load dboards
- _rx_dboard_proxy = wax_obj_proxy::make(
- boost::bind(&usrp2_mboard_impl::rx_dboard_get, this, _1, _2),
- boost::bind(&usrp2_mboard_impl::rx_dboard_set, this, _1, _2)
- );
- _tx_dboard_proxy = wax_obj_proxy::make(
- boost::bind(&usrp2_mboard_impl::tx_dboard_get, this, _1, _2),
- boost::bind(&usrp2_mboard_impl::tx_dboard_set, this, _1, _2)
- );
-}
-
-/***********************************************************************
- * RX DBoard Properties
- **********************************************************************/
-void usrp2_mboard_impl::rx_dboard_get(const wax::obj &key_, wax::obj &val){
- named_prop_t key = named_prop_t::extract(key_);
-
- //handle the get request conditioned on the key
- switch(key.as<dboard_prop_t>()){
- case DBOARD_PROP_NAME:
- val = _iface->get_cname() + " dboard (rx unit)";
- return;
-
- case DBOARD_PROP_SUBDEV:
- val = _dboard_manager->get_rx_subdev(key.name);
- return;
-
- case DBOARD_PROP_SUBDEV_NAMES:
- val = _dboard_manager->get_rx_subdev_names();
- return;
-
- case DBOARD_PROP_DBOARD_EEPROM:
- val = _rx_db_eeprom;
- return;
-
- case DBOARD_PROP_DBOARD_IFACE:
- val = _dboard_iface;
- return;
-
- case DBOARD_PROP_CODEC:
- val = _rx_codec_proxy->get_link();
- return;
-
- case DBOARD_PROP_GAIN_GROUP:
- val = make_gain_group(
- _rx_db_eeprom.id,
- _dboard_manager->get_rx_subdev(key.name),
- _rx_codec_proxy->get_link(),
- GAIN_GROUP_POLICY_RX
- );
- 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_DBOARD_EEPROM:
- _rx_db_eeprom = val.as<dboard_eeprom_t>();
- _rx_db_eeprom.store(*_iface, USRP2_I2C_ADDR_RX_DB);
- return;
-
- default: UHD_THROW_PROP_SET_ERROR();
- }
-}
-
-/***********************************************************************
- * TX DBoard Properties
- **********************************************************************/
-void usrp2_mboard_impl::tx_dboard_get(const wax::obj &key_, wax::obj &val){
- named_prop_t key = named_prop_t::extract(key_);
-
- //handle the get request conditioned on the key
- switch(key.as<dboard_prop_t>()){
- case DBOARD_PROP_NAME:
- val = _iface->get_cname() + " dboard (tx unit)";
- return;
-
- case DBOARD_PROP_SUBDEV:
- val = _dboard_manager->get_tx_subdev(key.name);
- return;
-
- case DBOARD_PROP_SUBDEV_NAMES:
- val = _dboard_manager->get_tx_subdev_names();
- return;
-
- case DBOARD_PROP_DBOARD_EEPROM:
- val = _tx_db_eeprom;
- return;
-
- case DBOARD_PROP_GBOARD_EEPROM:
- val = _gdb_eeprom;
- return;
-
- case DBOARD_PROP_DBOARD_IFACE:
- val = _dboard_iface;
- return;
-
- case DBOARD_PROP_CODEC:
- val = _tx_codec_proxy->get_link();
- return;
-
- case DBOARD_PROP_GAIN_GROUP:
- val = make_gain_group(
- _tx_db_eeprom.id,
- _dboard_manager->get_tx_subdev(key.name),
- _tx_codec_proxy->get_link(),
- GAIN_GROUP_POLICY_TX
- );
- 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_DBOARD_EEPROM:
- _tx_db_eeprom = val.as<dboard_eeprom_t>();
- _tx_db_eeprom.store(*_iface, USRP2_I2C_ADDR_TX_DB);
- return;
-
- case DBOARD_PROP_GBOARD_EEPROM:
- _gdb_eeprom = val.as<dboard_eeprom_t>();
- _gdb_eeprom.store(*_iface, USRP2_I2C_ADDR_TX_DB ^ 5);
- return;
-
- default: UHD_THROW_PROP_SET_ERROR();
- }
-}
diff --git a/host/lib/usrp/usrp2/dsp_impl.cpp b/host/lib/usrp/usrp2/dsp_impl.cpp
deleted file mode 100644
index 03cdeae42..000000000
--- a/host/lib/usrp/usrp2/dsp_impl.cpp
+++ /dev/null
@@ -1,262 +0,0 @@
-//
-// Copyright 2010-2011 Ettus Research LLC
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// 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 "usrp2_regs.hpp"
-#include <uhd/usrp/dsp_utils.hpp>
-#include <uhd/usrp/dsp_props.hpp>
-#include <boost/bind.hpp>
-#include <boost/math/special_functions/round.hpp>
-#include <boost/math/special_functions/sign.hpp>
-#include <algorithm>
-#include <cmath>
-
-using namespace uhd;
-using namespace uhd::usrp;
-
-/***********************************************************************
- * DSP impl and methods
- **********************************************************************/
-struct usrp2_mboard_impl::dsp_impl{
- uhd::dict<size_t, size_t> ddc_decim;
- uhd::dict<size_t, double> ddc_freq;
- uhd::dict<size_t, size_t> duc_interp;
- uhd::dict<size_t, double> duc_freq;
- std::vector<size_t> decim_and_interp_rates;
- uhd::dict<size_t, bool> continuous_streaming;
-};
-
-void usrp2_mboard_impl::dsp_init(void){
- //create new dsp impl
- _dsp_impl = UHD_PIMPL_MAKE(dsp_impl, ());
-
- //load the allowed decim/interp rates
- //range(4, 128+1, 1) + range(130, 256+1, 2) + range(260, 512+1, 4)
- for (size_t i = 4; i <= 128; i+=1){
- _dsp_impl->decim_and_interp_rates.push_back(i);
- }
- for (size_t i = 130; i <= 256; i+=2){
- _dsp_impl->decim_and_interp_rates.push_back(i);
- }
- for (size_t i = 260; i <= 512; i+=4){
- _dsp_impl->decim_and_interp_rates.push_back(i);
- }
-
- //bind and initialize the rx dsps
- for (size_t i = 0; i < NUM_RX_DSPS; i++){
- _rx_dsp_proxies[str(boost::format("DSP%d")%i)] = wax_obj_proxy::make(
- boost::bind(&usrp2_mboard_impl::ddc_get, this, _1, _2, i),
- boost::bind(&usrp2_mboard_impl::ddc_set, this, _1, _2, i)
- );
-
- //initial config and update
- ddc_set(DSP_PROP_FREQ_SHIFT, double(0), i);
- ddc_set(DSP_PROP_HOST_RATE, double(get_master_clock_freq()/16), i);
-
- //setup the rx control registers
- _iface->poke32(U2_REG_RX_CTRL_CLEAR(i), 1); //reset
- _iface->poke32(U2_REG_RX_CTRL_NSAMPS_PP(i), _device.get_max_recv_samps_per_packet());
- _iface->poke32(U2_REG_RX_CTRL_NCHANNELS(i), 1);
- _iface->poke32(U2_REG_RX_CTRL_VRT_HDR(i), 0
- | (0x1 << 28) //if data with stream id
- | (0x1 << 26) //has trailer
- | (0x3 << 22) //integer time other
- | (0x1 << 20) //fractional time sample count
- );
- _iface->poke32(U2_REG_RX_CTRL_VRT_SID(i), usrp2_impl::RECV_SID);
- _iface->poke32(U2_REG_RX_CTRL_VRT_TLR(i), 0);
- _iface->poke32(U2_REG_TIME64_TPS, size_t(get_master_clock_freq()));
- }
-
- //bind and initialize the tx dsps
- for (size_t i = 0; i < NUM_TX_DSPS; i++){
- _tx_dsp_proxies[str(boost::format("DSP%d")%i)] = wax_obj_proxy::make(
- boost::bind(&usrp2_mboard_impl::duc_get, this, _1, _2, i),
- boost::bind(&usrp2_mboard_impl::duc_set, this, _1, _2, i)
- );
-
- //initial config and update
- duc_set(DSP_PROP_FREQ_SHIFT, double(0), i);
- duc_set(DSP_PROP_HOST_RATE, double(get_master_clock_freq()/16), i);
-
- //init the tx control registers
- _iface->poke32(U2_REG_TX_CTRL_CLEAR_STATE, 1); //reset
- _iface->poke32(U2_REG_TX_CTRL_NUM_CHAN, 0); //1 channel
- _iface->poke32(U2_REG_TX_CTRL_REPORT_SID, usrp2_impl::ASYNC_SID);
- _iface->poke32(U2_REG_TX_CTRL_POLICY, U2_FLAG_TX_CTRL_POLICY_NEXT_PACKET);
- }
-}
-
-template <typename rate_type>
-static rate_type pick_closest_rate(double exact_rate, const std::vector<rate_type> &rates){
- unsigned closest_match = rates.front();
- BOOST_FOREACH(rate_type possible_rate, rates){
- if(std::abs(exact_rate - possible_rate) < std::abs(exact_rate - closest_match))
- closest_match = possible_rate;
- }
- return closest_match;
-}
-
-void usrp2_mboard_impl::issue_ddc_stream_cmd(const stream_cmd_t &stream_cmd, size_t which_dsp){
- _dsp_impl->continuous_streaming[which_dsp] = stream_cmd.stream_mode == stream_cmd_t::STREAM_MODE_START_CONTINUOUS;
- _iface->poke32(U2_REG_RX_CTRL_STREAM_CMD(which_dsp), dsp_type1::calc_stream_cmd_word(stream_cmd));
- _iface->poke32(U2_REG_RX_CTRL_TIME_SECS(which_dsp), boost::uint32_t(stream_cmd.time_spec.get_full_secs()));
- _iface->poke32(U2_REG_RX_CTRL_TIME_TICKS(which_dsp), stream_cmd.time_spec.get_tick_count(get_master_clock_freq()));
-}
-
-/***********************************************************************
- * DDC Properties
- **********************************************************************/
-void usrp2_mboard_impl::ddc_get(const wax::obj &key_, wax::obj &val, size_t which_dsp){
- named_prop_t key = named_prop_t::extract(key_);
-
- switch(key.as<dsp_prop_t>()){
- case DSP_PROP_NAME:
- val = str(boost::format("%s ddc%d") % _iface->get_cname() % which_dsp);
- return;
-
- case DSP_PROP_OTHERS:
- val = prop_names_t(); //empty
- return;
-
- case DSP_PROP_FREQ_SHIFT:
- val = _dsp_impl->ddc_freq[which_dsp];
- return;
-
- case DSP_PROP_CODEC_RATE:
- val = get_master_clock_freq();
- return;
-
- case DSP_PROP_HOST_RATE:
- val = get_master_clock_freq()/_dsp_impl->ddc_decim[which_dsp];
- return;
-
- default: UHD_THROW_PROP_GET_ERROR();
- }
-}
-
-void usrp2_mboard_impl::ddc_set(const wax::obj &key_, const wax::obj &val, size_t which_dsp){
- named_prop_t key = named_prop_t::extract(key_);
-
- switch(key.as<dsp_prop_t>()){
-
- case DSP_PROP_STREAM_CMD:
- issue_ddc_stream_cmd(val.as<stream_cmd_t>(), which_dsp);
- return;
-
- case DSP_PROP_FREQ_SHIFT:{
- double new_freq = val.as<double>();
- _iface->poke32(U2_REG_DSP_RX_FREQ(which_dsp),
- dsp_type1::calc_cordic_word_and_update(new_freq, get_master_clock_freq())
- );
- _dsp_impl->ddc_freq[which_dsp] = new_freq; //shadow
- }
- return;
-
- case DSP_PROP_HOST_RATE:{
- double extact_rate = get_master_clock_freq()/val.as<double>();
- _dsp_impl->ddc_decim[which_dsp] = pick_closest_rate(extact_rate, _dsp_impl->decim_and_interp_rates);
-
- //set the decimation
- _iface->poke32(U2_REG_DSP_RX_DECIM(which_dsp), dsp_type1::calc_cic_filter_word(_dsp_impl->ddc_decim[which_dsp]));
-
- //set the scaling
- static const boost::int16_t default_rx_scale_iq = 1024;
- _iface->poke32(U2_REG_DSP_RX_SCALE_IQ(which_dsp),
- dsp_type1::calc_iq_scale_word(default_rx_scale_iq, default_rx_scale_iq)
- );
- }
- _device.update_xport_channel_mapping(); //rate changed -> update
- return;
-
- default: UHD_THROW_PROP_SET_ERROR();
- }
-}
-
-/***********************************************************************
- * DUC Properties
- **********************************************************************/
-void usrp2_mboard_impl::duc_get(const wax::obj &key_, wax::obj &val, size_t which_dsp){
- named_prop_t key = named_prop_t::extract(key_);
-
- switch(key.as<dsp_prop_t>()){
- case DSP_PROP_NAME:
- val = str(boost::format("%s duc%d") % _iface->get_cname() % which_dsp);
- return;
-
- case DSP_PROP_OTHERS:
- val = prop_names_t(); //empty
- return;
-
- case DSP_PROP_FREQ_SHIFT:
- val = _dsp_impl->duc_freq[which_dsp];
- return;
-
- case DSP_PROP_CODEC_RATE:
- val = get_master_clock_freq();
- return;
-
- case DSP_PROP_HOST_RATE:
- val = get_master_clock_freq()/_dsp_impl->duc_interp[which_dsp];
- return;
-
- default: UHD_THROW_PROP_GET_ERROR();
- }
-}
-
-void usrp2_mboard_impl::duc_set(const wax::obj &key_, const wax::obj &val, size_t which_dsp){
- named_prop_t key = named_prop_t::extract(key_);
-
- switch(key.as<dsp_prop_t>()){
-
- case DSP_PROP_FREQ_SHIFT:{
- const double codec_rate = get_master_clock_freq();
- double new_freq = val.as<double>();
-
- //calculate the DAC shift (multiples of rate)
- const int sign = boost::math::sign(new_freq);
- const int zone = std::min(boost::math::iround(new_freq/codec_rate), 2);
- const double dac_shift = sign*zone*codec_rate;
- new_freq -= dac_shift; //update FPGA DSP target freq
-
- //set the DAC shift (modulation mode)
- if (zone == 0) _codec_ctrl->set_tx_mod_mode(0); //no shift
- else _codec_ctrl->set_tx_mod_mode(sign*4/zone); //DAC interp = 4
-
- _iface->poke32(U2_REG_DSP_TX_FREQ,
- dsp_type1::calc_cordic_word_and_update(new_freq, codec_rate)
- );
- _dsp_impl->duc_freq[which_dsp] = new_freq + dac_shift; //shadow
- }
- return;
-
- case DSP_PROP_HOST_RATE:{
- double extact_rate = get_master_clock_freq()/val.as<double>();
- _dsp_impl->duc_interp[which_dsp] = pick_closest_rate(extact_rate, _dsp_impl->decim_and_interp_rates);
-
- //set the interpolation
- _iface->poke32(U2_REG_DSP_TX_INTERP_RATE, dsp_type1::calc_cic_filter_word(_dsp_impl->duc_interp[which_dsp]));
-
- //set the scaling
- _iface->poke32(U2_REG_DSP_TX_SCALE_IQ, dsp_type1::calc_iq_scale_word(_dsp_impl->duc_interp[which_dsp]));
- }
- _device.update_xport_channel_mapping(); //rate changed -> update
- 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 e5c60f27c..83f4a1048 100644
--- a/host/lib/usrp/usrp2/fw_common.h
+++ b/host/lib/usrp/usrp2/fw_common.h
@@ -30,8 +30,9 @@ extern "C" {
#endif
//fpga and firmware compatibility numbers
-#define USRP2_FPGA_COMPAT_NUM 6
+#define USRP2_FPGA_COMPAT_NUM 7
#define USRP2_FW_COMPAT_NUM 10
+#define USRP2_FW_VER_MINOR 1
//used to differentiate control packets over data port
#define USRP2_INVALID_VRT_HEADER 0
@@ -40,9 +41,14 @@ extern "C" {
// Dynamic and/or private ports: 49152-65535
#define USRP2_UDP_CTRL_PORT 49152
//#define USRP2_UDP_UPDATE_PORT 49154
-#define USRP2_UDP_DSP0_PORT 49156
-#define USRP2_UDP_ERR0_PORT 49157
-#define USRP2_UDP_DSP1_PORT 49158
+#define USRP2_UDP_RX_DSP0_PORT 49156
+#define USRP2_UDP_TX_DSP0_PORT 49157
+#define USRP2_UDP_RX_DSP1_PORT 49158
+
+// Map for virtual firmware regs (not very big so we can keep it here for now)
+#define U2_FW_REG_LOCK_TIME 0
+#define U2_FW_REG_LOCK_GPID 1
+#define U2_FW_REG_VER_MINOR 7
////////////////////////////////////////////////////////////////////////
// I2C addresses
diff --git a/host/lib/usrp/usrp2/io_impl.cpp b/host/lib/usrp/usrp2/io_impl.cpp
index df452942c..7e855d1bd 100644
--- a/host/lib/usrp/usrp2/io_impl.cpp
+++ b/host/lib/usrp/usrp2/io_impl.cpp
@@ -15,23 +15,22 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
+#include "validate_subdev_spec.hpp"
#include "../../transport/super_recv_packet_handler.hpp"
#include "../../transport/super_send_packet_handler.hpp"
#include "usrp2_impl.hpp"
#include "usrp2_regs.hpp"
#include <uhd/utils/log.hpp>
#include <uhd/utils/msg.hpp>
+#include <uhd/utils/tasks.hpp>
#include <uhd/exception.hpp>
-#include <uhd/usrp/mboard_props.hpp>
-#include <uhd/usrp/dsp_props.hpp>
#include <uhd/utils/byteswap.hpp>
#include <uhd/utils/thread_priority.hpp>
#include <uhd/transport/bounded_buffer.hpp>
+#include <boost/thread/thread.hpp>
#include <boost/format.hpp>
#include <boost/bind.hpp>
#include <boost/thread/mutex.hpp>
-#include <boost/thread/thread.hpp>
-#include <boost/thread/barrier.hpp>
#include <iostream>
using namespace uhd;
@@ -54,11 +53,6 @@ static UHD_INLINE double from_time_dur(const pt::time_duration &time_dur){
/***********************************************************************
* constants
**********************************************************************/
-static const int underflow_flags = 0
- | async_metadata_t::EVENT_CODE_UNDERFLOW
- | async_metadata_t::EVENT_CODE_UNDERFLOW_IN_PACKET
-;
-
static const size_t vrt_send_header_offset_words32 = 1;
/***********************************************************************
@@ -134,31 +128,20 @@ private:
**********************************************************************/
struct usrp2_impl::io_impl{
- io_impl(std::vector<zero_copy_if::sptr> &dsp_xports):
- dsp_xports(dsp_xports), //the assumption is that all data transports should be identical
+ io_impl(void):
async_msg_fifo(100/*messages deep*/)
{
- for (size_t i = 0; i < dsp_xports.size(); i++){
- fc_mons.push_back(flow_control_monitor::sptr(new flow_control_monitor(
- usrp2_impl::sram_bytes/dsp_xports.front()->get_send_frame_size()
- )));
- }
- }
-
- ~io_impl(void){
- recv_pirate_crew.interrupt_all();
- recv_pirate_crew.join_all();
+ /* NOP */
}
managed_send_buffer::sptr get_send_buff(size_t chan, double timeout){
- const size_t index = send_map[chan];
- flow_control_monitor &fc_mon = *fc_mons[index];
+ flow_control_monitor &fc_mon = *fc_mons[chan];
//wait on flow control w/ timeout
if (not fc_mon.check_fc_condition(timeout)) return managed_send_buffer::sptr();
//get a buffer from the transport w/ timeout
- managed_send_buffer::sptr buff = dsp_xports[index]->get_send_buff(timeout);
+ managed_send_buffer::sptr buff = tx_xports[chan]->get_send_buff(timeout);
//write the flow control word into the buffer
if (buff.get()) buff->cast<boost::uint32_t *>()[0] = uhd::htonx(fc_mon.get_curr_seq_out());
@@ -166,15 +149,8 @@ struct usrp2_impl::io_impl{
return buff;
}
- std::vector<zero_copy_if::sptr> &dsp_xports;
-
- //mappings from channel index to dsp xport
- std::vector<size_t> send_map, recv_map;
-
- //previous state for each buffer
- std::vector<vrt::if_packet_info_t> prev_infos;
-
- //flow control monitors
+ //tx dsp: xports and flow control monitors
+ std::vector<zero_copy_if::sptr> tx_xports;
std::vector<flow_control_monitor::sptr> fc_mons;
//state management for the vrt packet handler code
@@ -182,9 +158,10 @@ struct usrp2_impl::io_impl{
sph::send_packet_handler send_handler;
//methods and variables for the pirate crew
- void recv_pirate_loop(boost::barrier &, usrp2_mboard_impl::sptr, zero_copy_if::sptr, size_t);
- boost::thread_group recv_pirate_crew;
+ void recv_pirate_loop(zero_copy_if::sptr, size_t);
+ std::list<task::sptr> pirate_tasks;
bounded_buffer<async_metadata_t> async_msg_fifo;
+ double tick_rate;
};
/***********************************************************************
@@ -194,16 +171,12 @@ struct usrp2_impl::io_impl{
* - put async message packets into queue
**********************************************************************/
void usrp2_impl::io_impl::recv_pirate_loop(
- boost::barrier &spawn_barrier,
- usrp2_mboard_impl::sptr mboard,
- zero_copy_if::sptr err_xport,
- size_t index
+ zero_copy_if::sptr err_xport, size_t index
){
- spawn_barrier.wait();
set_thread_priority_safe();
//store a reference to the flow control monitor (offset by max dsps)
- flow_control_monitor &fc_mon = *(this->fc_mons[index*usrp2_mboard_impl::MAX_NUM_DSPS]);
+ flow_control_monitor &fc_mon = *(this->fc_mons[index]);
while (not boost::this_thread::interruption_requested()){
managed_recv_buffer::sptr buff = err_xport->get_recv_buff();
@@ -217,14 +190,14 @@ void usrp2_impl::io_impl::recv_pirate_loop(
vrt::if_hdr_unpack_be(vrt_hdr, if_packet_info);
//handle a tx async report message
- if (if_packet_info.sid == usrp2_impl::ASYNC_SID and if_packet_info.packet_type != vrt::if_packet_info_t::PACKET_TYPE_DATA){
+ if (if_packet_info.sid == USRP2_TX_ASYNC_SID 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()
+ time_t(if_packet_info.tsi), size_t(if_packet_info.tsf), tick_rate
);
metadata.event_code = async_metadata_t::event_code_t(sph::get_context_code(vrt_hdr, if_packet_info));
@@ -234,17 +207,23 @@ void usrp2_impl::io_impl::recv_pirate_loop(
fc_mon.update_fc_condition(uhd::ntohx(fc_word32));
continue;
}
-
- //print the famous U, and push the metadata into the message queue
- if (metadata.event_code & underflow_flags) UHD_MSG(fastpath) << "U";
//else UHD_MSG(often) << "metadata.event_code " << metadata.event_code << std::endl;
async_msg_fifo.push_with_pop_on_full(metadata);
+
+ if (metadata.event_code &
+ ( async_metadata_t::EVENT_CODE_UNDERFLOW
+ | async_metadata_t::EVENT_CODE_UNDERFLOW_IN_PACKET)
+ ) UHD_MSG(fastpath) << "U";
+ else if (metadata.event_code &
+ ( async_metadata_t::EVENT_CODE_SEQ_ERROR
+ | async_metadata_t::EVENT_CODE_SEQ_ERROR_IN_BURST)
+ ) UHD_MSG(fastpath) << "S";
}
else{
//TODO unknown received packet, may want to print error...
}
}catch(const std::exception &e){
- UHD_MSG(error) << "Error (usrp2 recv pirate loop): " << e.what() << std::endl;
+ UHD_MSG(error) << "Error in recv pirate loop: " << e.what() << std::endl;
}
}
}
@@ -254,80 +233,150 @@ void usrp2_impl::io_impl::recv_pirate_loop(
**********************************************************************/
void usrp2_impl::io_init(void){
+ //setup rx otw type
+ _rx_otw_type.width = 16;
+ _rx_otw_type.shift = 0;
+ _rx_otw_type.byteorder = uhd::otw_type_t::BO_BIG_ENDIAN;
+
+ //setup tx otw type
+ _tx_otw_type.width = 16;
+ _tx_otw_type.shift = 0;
+ _tx_otw_type.byteorder = uhd::otw_type_t::BO_BIG_ENDIAN;
+
//create new io impl
- _io_impl = UHD_PIMPL_MAKE(io_impl, (dsp_xports));
+ _io_impl = UHD_PIMPL_MAKE(io_impl, ());
+
+ //init first so we dont have an access race
+ BOOST_FOREACH(const std::string &mb, _mbc.keys()){
+ //init the tx xport and flow control monitor
+ _io_impl->tx_xports.push_back(_mbc[mb].tx_dsp_xport);
+ _io_impl->fc_mons.push_back(flow_control_monitor::sptr(new flow_control_monitor(
+ USRP2_SRAM_BYTES/_mbc[mb].tx_dsp_xport->get_send_frame_size()
+ )));
+ }
//create a new pirate thread for each zc if (yarr!!)
- boost::barrier spawn_barrier(_mboards.size()+1);
- for (size_t i = 0; i < _mboards.size(); i++){
+ size_t index = 0;
+ BOOST_FOREACH(const std::string &mb, _mbc.keys()){
//spawn a new pirate to plunder the recv booty
- _io_impl->recv_pirate_crew.create_thread(boost::bind(
- &usrp2_impl::io_impl::recv_pirate_loop,
- _io_impl.get(), boost::ref(spawn_barrier),
- _mboards.at(i), err_xports.at(i), i
- ));
+ _io_impl->pirate_tasks.push_back(task::make(boost::bind(
+ &usrp2_impl::io_impl::recv_pirate_loop, _io_impl.get(),
+ _mbc[mb].tx_dsp_xport, index++
+ )));
}
- spawn_barrier.wait();
- //update mapping here since it didnt b4 when io init not called first
- update_xport_channel_mapping();
-}
+ //init some handler stuff
+ _io_impl->recv_handler.set_vrt_unpacker(&vrt::if_hdr_unpack_be);
+ _io_impl->recv_handler.set_converter(_rx_otw_type);
+ _io_impl->send_handler.set_vrt_packer(&vrt::if_hdr_pack_be, vrt_send_header_offset_words32);
+ _io_impl->send_handler.set_converter(_tx_otw_type);
+ _io_impl->send_handler.set_max_samples_per_packet(get_max_send_samps_per_packet());
-void usrp2_impl::update_xport_channel_mapping(void){
- if (_io_impl.get() == NULL) return; //not inited yet
+ //set the packet threshold to be an entire socket buffer's worth
+ const size_t packets_per_sock_buff = 50e6/_mbc[_mbc.keys().front()].rx_dsp_xports[0]->get_recv_frame_size();
+ _io_impl->recv_handler.set_alignment_failure_threshold(packets_per_sock_buff);
+}
- _io_impl->recv_map.clear();
- _io_impl->send_map.clear();
+void usrp2_impl::update_tick_rate(const double rate){
+ _io_impl->tick_rate = rate;
+ boost::mutex::scoped_lock recv_lock = _io_impl->recv_handler.get_scoped_lock();
+ _io_impl->recv_handler.set_tick_rate(rate);
+ boost::mutex::scoped_lock send_lock = _io_impl->send_handler.get_scoped_lock();
+ _io_impl->send_handler.set_tick_rate(rate);
+}
- for (size_t i = 0; i < _mboards.size(); i++){
+void usrp2_impl::update_rx_samp_rate(const double rate){
+ boost::mutex::scoped_lock recv_lock = _io_impl->recv_handler.get_scoped_lock();
+ _io_impl->recv_handler.set_samp_rate(rate);
+ const double adj = _mbc[_mbc.keys().front()].rx_dsps.front()->get_scaling_adjustment();
+ _io_impl->recv_handler.set_scale_factor(adj/32767.);
+}
- subdev_spec_t rx_subdev_spec = _mboards[i]->get_link()[MBOARD_PROP_RX_SUBDEV_SPEC].as<subdev_spec_t>();
- for (size_t j = 0; j < rx_subdev_spec.size(); j++){
- _io_impl->recv_map.push_back(i*usrp2_mboard_impl::MAX_NUM_DSPS+j);
- UHD_LOG << "recv_map.back() " << _io_impl->recv_map.back() << std::endl;
- }
+void usrp2_impl::update_tx_samp_rate(const double rate){
+ boost::mutex::scoped_lock send_lock = _io_impl->send_handler.get_scoped_lock();
+ _io_impl->send_handler.set_samp_rate(rate);
+}
- subdev_spec_t tx_subdev_spec = _mboards[i]->get_link()[MBOARD_PROP_TX_SUBDEV_SPEC].as<subdev_spec_t>();
- for (size_t j = 0; j < tx_subdev_spec.size(); j++){
- _io_impl->send_map.push_back(i*usrp2_mboard_impl::MAX_NUM_DSPS+j);
- UHD_LOG << "send_map.back() " << _io_impl->send_map.back() << std::endl;
+static subdev_spec_t replace_zero_in_spec(const std::string &type, const subdev_spec_t &spec){
+ subdev_spec_t new_spec;
+ BOOST_FOREACH(const subdev_spec_pair_t &pair, spec){
+ if (pair.db_name == "0"){
+ UHD_MSG(warning)
+ << boost::format("In the %s subdevice specification: %s") % type % spec.to_string() << std::endl
+ << "Accepting dboard slot name \"0\" for backward compatibility." << std::endl
+ << "The official name of the dboard slot on USRP2/N-Series is \"A\"." << std::endl
+ ;
+ new_spec.push_back(subdev_spec_pair_t("A", pair.sd_name));
}
-
+ else new_spec.push_back(pair);
}
+ return new_spec;
+}
- //set all of the relevant properties on the handler
+subdev_spec_t usrp2_impl::update_rx_subdev_spec(const std::string &which_mb, const subdev_spec_t &spec_){
+ const subdev_spec_t spec = replace_zero_in_spec("RX", spec_);
boost::mutex::scoped_lock recv_lock = _io_impl->recv_handler.get_scoped_lock();
- _io_impl->recv_handler.resize(_io_impl->recv_map.size());
- _io_impl->recv_handler.set_vrt_unpacker(&vrt::if_hdr_unpack_be);
- _io_impl->recv_handler.set_tick_rate(_mboards.front()->get_master_clock_freq());
- //TODO temporarily use the first dsp rate until we support non-homo rates
- const std::string rx_dsp_name = _mboards.at(0)->get_link()[MBOARD_PROP_RX_DSP_NAMES].as<prop_names_t>().at(0);
- const double rx_host_rate = _mboards.at(0)->get_link()[named_prop_t(MBOARD_PROP_RX_DSP, rx_dsp_name)][DSP_PROP_HOST_RATE].as<double>();
- _io_impl->recv_handler.set_samp_rate(rx_host_rate);
- for (size_t chan = 0; chan < _io_impl->recv_handler.size(); chan++){
- _io_impl->recv_handler.set_xport_chan_get_buff(chan, boost::bind(
- &uhd::transport::zero_copy_if::get_recv_buff,
- _io_impl->dsp_xports[_io_impl->recv_map[chan]], _1
- ));
+ property_tree::path_type root = "/mboards/" + which_mb + "/dboards";
+
+ //sanity checking
+ validate_subdev_spec(_tree, spec, "rx", which_mb);
+
+ //setup mux for this spec
+ bool fe_swapped = false;
+ for (size_t i = 0; i < spec.size(); i++){
+ const std::string conn = _tree->access<std::string>(root / spec[i].db_name / "rx_frontends" / spec[i].sd_name / "connection").get();
+ if (i == 0 and (conn == "QI" or conn == "Q")) fe_swapped = true;
+ _mbc[which_mb].rx_dsps[i]->set_mux(conn, fe_swapped);
}
- _io_impl->recv_handler.set_converter(_rx_otw_type);
+ _mbc[which_mb].rx_fe->set_mux(fe_swapped);
+
+ //compute the new occupancy and resize
+ _mbc[which_mb].rx_chan_occ = spec.size();
+ size_t nchan = 0;
+ BOOST_FOREACH(const std::string &mb, _mbc.keys()) nchan += _mbc[mb].rx_chan_occ;
+ _io_impl->recv_handler.resize(nchan);
+
+ //bind new callbacks for the handler
+ size_t chan = 0;
+ BOOST_FOREACH(const std::string &mb, _mbc.keys()){
+ for (size_t dsp = 0; dsp < _mbc[mb].rx_chan_occ; dsp++){
+ _mbc[mb].rx_dsps[dsp]->set_nsamps_per_packet(get_max_recv_samps_per_packet()); //seems to be a good place to set this
+ _io_impl->recv_handler.set_xport_chan_get_buff(chan++, boost::bind(
+ &zero_copy_if::get_recv_buff, _mbc[mb].rx_dsp_xports[dsp], _1
+ ));
+ }
+ }
+ return spec;
+}
- //set all of the relevant properties on the handler
+subdev_spec_t usrp2_impl::update_tx_subdev_spec(const std::string &which_mb, const subdev_spec_t &spec_){
+ const subdev_spec_t spec = replace_zero_in_spec("TX", spec_);
boost::mutex::scoped_lock send_lock = _io_impl->send_handler.get_scoped_lock();
- _io_impl->send_handler.resize(_io_impl->send_map.size());
- _io_impl->send_handler.set_vrt_packer(&vrt::if_hdr_pack_be, vrt_send_header_offset_words32);
- _io_impl->send_handler.set_tick_rate(_mboards.front()->get_master_clock_freq());
- //TODO temporarily use the first dsp rate until we support non-homo rates
- const std::string tx_dsp_name = _mboards.at(0)->get_link()[MBOARD_PROP_TX_DSP_NAMES].as<prop_names_t>().at(0);
- const double tx_host_rate = _mboards.at(0)->get_link()[named_prop_t(MBOARD_PROP_TX_DSP, tx_dsp_name)][DSP_PROP_HOST_RATE].as<double>();
- _io_impl->send_handler.set_samp_rate(tx_host_rate);
- for (size_t chan = 0; chan < _io_impl->send_handler.size(); chan++){
- _io_impl->send_handler.set_xport_chan_get_buff(chan, boost::bind(
- &usrp2_impl::io_impl::get_send_buff, _io_impl.get(), chan, _1
- ));
+ property_tree::path_type root = "/mboards/" + which_mb + "/dboards";
+
+ //sanity checking
+ validate_subdev_spec(_tree, spec, "tx", which_mb);
+
+ //set the mux for this spec
+ const std::string conn = _tree->access<std::string>(root / spec[0].db_name / "tx_frontends" / spec[0].sd_name / "connection").get();
+ _mbc[which_mb].tx_fe->set_mux(conn);
+
+ //compute the new occupancy and resize
+ _mbc[which_mb].tx_chan_occ = spec.size();
+ size_t nchan = 0;
+ BOOST_FOREACH(const std::string &mb, _mbc.keys()) nchan += _mbc[mb].tx_chan_occ;
+ _io_impl->send_handler.resize(nchan);
+
+ //bind new callbacks for the handler
+ size_t chan = 0, i = 0;
+ BOOST_FOREACH(const std::string &mb, _mbc.keys()){
+ for (size_t dsp = 0; dsp < _mbc[mb].tx_chan_occ; dsp++){
+ _io_impl->send_handler.set_xport_chan_get_buff(chan++, boost::bind(
+ &usrp2_impl::io_impl::get_send_buff, _io_impl.get(), i++, _1
+ ));
+ }
}
- _io_impl->send_handler.set_converter(_tx_otw_type);
- _io_impl->send_handler.set_max_samples_per_packet(get_max_send_samps_per_packet());
+ return spec;
}
/***********************************************************************
@@ -349,7 +398,7 @@ size_t usrp2_impl::get_max_send_samps_per_packet(void) const{
+ vrt_send_header_offset_words32*sizeof(boost::uint32_t)
- sizeof(vrt::if_packet_info_t().cid) //no class id ever used
;
- const size_t bpp = dsp_xports.front()->get_send_frame_size() - hdr_size;
+ const size_t bpp = _mbc[_mbc.keys().front()].tx_dsp_xport->get_send_frame_size() - hdr_size;
return bpp/_tx_otw_type.get_sample_size();
}
@@ -374,7 +423,7 @@ size_t usrp2_impl::get_max_recv_samps_per_packet(void) const{
+ sizeof(vrt::if_packet_info_t().tlr) //forced to have trailer
- sizeof(vrt::if_packet_info_t().cid) //no class id ever used
;
- const size_t bpp = dsp_xports.front()->get_recv_frame_size() - hdr_size;
+ const size_t bpp = _mbc[_mbc.keys().front()].rx_dsp_xports[0]->get_recv_frame_size() - hdr_size;
return bpp/_rx_otw_type.get_sample_size();
}
diff --git a/host/lib/usrp/usrp2/mboard_impl.cpp b/host/lib/usrp/usrp2/mboard_impl.cpp
deleted file mode 100644
index 61ceb95ca..000000000
--- a/host/lib/usrp/usrp2/mboard_impl.cpp
+++ /dev/null
@@ -1,490 +0,0 @@
-//
-// Copyright 2010-2011 Ettus Research LLC
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// 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 "usrp2_regs.hpp"
-#include "fw_common.h"
-#include <uhd/utils/log.hpp>
-#include <uhd/utils/msg.hpp>
-#include <uhd/utils/safe_call.hpp>
-#include <uhd/exception.hpp>
-#include <uhd/usrp/gps_ctrl.hpp>
-#include <uhd/usrp/misc_utils.hpp>
-#include <uhd/usrp/dsp_utils.hpp>
-#include <uhd/usrp/mboard_props.hpp>
-#include <uhd/utils/byteswap.hpp>
-#include <uhd/utils/algorithm.hpp>
-#include <uhd/types/sensors.hpp>
-#include <boost/assign/list_of.hpp>
-#include <boost/bind.hpp>
-
-static const double mimo_clock_delay_usrp2_rev4 = 4.18e-9;
-static const double mimo_clock_delay_usrp_n2xx = 3.55e-9;
-static const size_t mimo_clock_sync_delay_cycles = 137;
-
-using namespace uhd;
-using namespace uhd::usrp;
-using namespace uhd::transport;
-
-/***********************************************************************
- * Helpers
- **********************************************************************/
-static void init_xport(zero_copy_if::sptr xport){
- //Send a small data packet so the usrp2 knows the udp source port.
- //This setup must happen before further initialization occurs
- //or the async update packets will cause ICMP destination unreachable.
- static const boost::uint32_t data[2] = {
- uhd::htonx(boost::uint32_t(0 /* don't care seq num */)),
- uhd::htonx(boost::uint32_t(USRP2_INVALID_VRT_HEADER))
- };
-
- transport::managed_send_buffer::sptr send_buff = xport->get_send_buff();
- std::memcpy(send_buff->cast<void*>(), &data, sizeof(data));
- send_buff->commit(sizeof(data));
-}
-
-/***********************************************************************
- * Structors
- **********************************************************************/
-usrp2_mboard_impl::usrp2_mboard_impl(
- const device_addr_t &device_addr,
- size_t index, usrp2_impl &device
-):
- _index(index), _device(device),
- _iface(usrp2_iface::make(udp_simple::make_connected(
- device_addr["addr"], BOOST_STRINGIZE(USRP2_UDP_CTRL_PORT)
- )))
-{
-
- //check the fpga compatibility number
- const boost::uint32_t fpga_compat_num = _iface->peek32(U2_REG_COMPAT_NUM_RB);
- if (fpga_compat_num != USRP2_FPGA_COMPAT_NUM){
- throw uhd::runtime_error(str(boost::format(
- "\nPlease update the firmware and FPGA images for your device.\n"
- "See the application notes for USRP2/N-Series for instructions.\n"
- "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));
- }
-
- //lock the device/motherboard to this process
- _iface->lock_device(true);
-
- //construct transports for dsp and async errors
- UHD_LOG << "Making transport for DSP0..." << std::endl;
- device.dsp_xports.push_back(udp_zero_copy::make(
- device_addr["addr"], BOOST_STRINGIZE(USRP2_UDP_DSP0_PORT), device_addr
- ));
- init_xport(device.dsp_xports.back());
-
- UHD_LOG << "Making transport for DSP1..." << std::endl;
- device.dsp_xports.push_back(udp_zero_copy::make(
- device_addr["addr"], BOOST_STRINGIZE(USRP2_UDP_DSP1_PORT), device_addr
- ));
- init_xport(device.dsp_xports.back());
-
- UHD_LOG << "Making transport for ERR0..." << std::endl;
- device.err_xports.push_back(udp_zero_copy::make(
- device_addr["addr"], BOOST_STRINGIZE(USRP2_UDP_ERR0_PORT), device_addr_t()
- ));
- init_xport(device.err_xports.back());
-
- //contruct the interfaces to mboard perifs
- _clock_ctrl = usrp2_clock_ctrl::make(_iface);
- _codec_ctrl = usrp2_codec_ctrl::make(_iface);
- if (_iface->mb_eeprom["gpsdo"] == "internal"){
- _gps_ctrl = gps_ctrl::make(
- _iface->get_gps_write_fn(),
- _iface->get_gps_read_fn());
- }
-
- //init the dsp stuff (before setting update packets)
- dsp_init();
-
- //setting the cycles per update (disabled by default)
- const double ups_per_sec = device_addr.cast<double>("ups_per_sec", 20);
- if (ups_per_sec > 0.0){
- const size_t cycles_per_up = size_t(_clock_ctrl->get_master_clock_rate()/ups_per_sec);
- _iface->poke32(U2_REG_TX_CTRL_CYCLES_PER_UP, U2_FLAG_TX_CTRL_UP_ENB | cycles_per_up);
- }
-
- //setting the packets per update (enabled by default)
- size_t send_frame_size = device.dsp_xports[0]->get_send_frame_size();
- const double ups_per_fifo = device_addr.cast<double>("ups_per_fifo", 8.0);
- if (ups_per_fifo > 0.0){
- const size_t packets_per_up = size_t(usrp2_impl::sram_bytes/ups_per_fifo/send_frame_size);
- _iface->poke32(U2_REG_TX_CTRL_PACKETS_PER_UP, U2_FLAG_TX_CTRL_UP_ENB | packets_per_up);
- }
-
- //initialize the clock configuration
- if (device_addr.has_key("mimo_mode")){
- if (device_addr["mimo_mode"] == "master"){
- _mimo_clocking_mode_is_master = true;
- }
- else if (device_addr["mimo_mode"] == "slave"){
- _mimo_clocking_mode_is_master = false;
- }
- else throw uhd::value_error(
- "mimo_mode must be set to master or slave"
- );
- }
- else {
- _mimo_clocking_mode_is_master = (_iface->peek32(U2_REG_STATUS) & (1 << 8)) != 0;
- }
- UHD_MSG(status) << boost::format("mboard%d is MIMO %s") % _index %
- (_mimo_clocking_mode_is_master?"master":"slave") << std::endl;
-
- //init the clock config
- if(_iface->mb_eeprom["gpsdo"] == "internal" or
- _iface->mb_eeprom["gpsdo"] == "external") {
- _clock_config = clock_config_t::external();
- }
- else {
- _clock_config = clock_config_t::internal();
- }
- update_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();
-
- //------------------------------------------------------------------
- //This is a hack/fix for the lingering packet problem.
- stream_cmd_t stream_cmd(stream_cmd_t::STREAM_MODE_NUM_SAMPS_AND_DONE);
- for (size_t i = 0; i < NUM_RX_DSPS; i++){
- size_t index = device.dsp_xports.size() - NUM_RX_DSPS + i;
- stream_cmd.num_samps = 1;
- this->issue_ddc_stream_cmd(stream_cmd, i);
- device.dsp_xports.at(index)->get_recv_buff(0.01).get(); //recv with timeout for lingering
- device.dsp_xports.at(index)->get_recv_buff(0.01).get(); //recv with timeout for expected
- _iface->poke32(U2_REG_RX_CTRL_CLEAR(i), 1); //resets sequence
- }
- //------------------------------------------------------------------
-
- //initialize VITA time to GPS time
- if( _gps_ctrl.get()
- and _gps_ctrl->gps_detected()) {
- UHD_MSG(status) << "Setting device time to GPS time...\n";
- set_time_spec(time_spec_t(double(_gps_ctrl->get_sensor("gps_time").to_int()+1)), false);
- }
-}
-
-usrp2_mboard_impl::~usrp2_mboard_impl(void){UHD_SAFE_CALL(
- _iface->poke32(U2_REG_TX_CTRL_CYCLES_PER_UP, 0);
- _iface->poke32(U2_REG_TX_CTRL_PACKETS_PER_UP, 0);
-)}
-
-/***********************************************************************
- * Helper Methods
- **********************************************************************/
-void usrp2_mboard_impl::update_clock_config(void){
- boost::uint32_t pps_flags = 0;
-
- //slave mode overrides clock config settings
- if (not _mimo_clocking_mode_is_master){
- _clock_config.ref_source = clock_config_t::REF_MIMO;
- _clock_config.pps_source = clock_config_t::PPS_MIMO;
- }
-
- //translate pps source enums
- switch(_clock_config.pps_source){
- case clock_config_t::PPS_MIMO:
- _iface->poke32(U2_REG_TIME64_MIMO_SYNC,
- (1 << 8) | (mimo_clock_sync_delay_cycles & 0xff)
- );
- break;
-
- case clock_config_t::PPS_SMA:
- _iface->poke32(U2_REG_TIME64_MIMO_SYNC, 0);
- pps_flags |= U2_FLAG_TIME64_PPS_SMA;
- break;
-
- default: throw uhd::value_error("unhandled clock configuration pps source");
- }
-
- //translate pps polarity enums
- switch(_clock_config.pps_polarity){
- case clock_config_t::PPS_POS: pps_flags |= U2_FLAG_TIME64_PPS_POSEDGE; break;
- case clock_config_t::PPS_NEG: pps_flags |= U2_FLAG_TIME64_PPS_NEGEDGE; break;
- default: throw uhd::value_error("unhandled clock configuration pps polarity");
- }
-
- //set the pps flags
- _iface->poke32(U2_REG_TIME64_FLAGS, pps_flags);
-
- //clock source ref 10mhz
- switch(_iface->get_rev()){
- case usrp2_iface::USRP_N200:
- case usrp2_iface::USRP_N210:
- case usrp2_iface::USRP_N200_R4:
- case usrp2_iface::USRP_N210_R4:
- switch(_clock_config.ref_source){
- case clock_config_t::REF_INT : _iface->poke32(U2_REG_MISC_CTRL_CLOCK, 0x12); break;
- case clock_config_t::REF_SMA : _iface->poke32(U2_REG_MISC_CTRL_CLOCK, 0x1C); break;
- case clock_config_t::REF_MIMO: _iface->poke32(U2_REG_MISC_CTRL_CLOCK, 0x15); break;
- default: throw uhd::value_error("unhandled clock configuration reference source");
- }
- _clock_ctrl->enable_external_ref(true); //USRP2P has an internal 10MHz TCXO
- break;
-
- case usrp2_iface::USRP2_REV3:
- case usrp2_iface::USRP2_REV4:
- switch(_clock_config.ref_source){
- case clock_config_t::REF_INT : _iface->poke32(U2_REG_MISC_CTRL_CLOCK, 0x10); break;
- case clock_config_t::REF_SMA : _iface->poke32(U2_REG_MISC_CTRL_CLOCK, 0x1C); break;
- case clock_config_t::REF_MIMO: _iface->poke32(U2_REG_MISC_CTRL_CLOCK, 0x15); break;
- default: throw uhd::value_error("unhandled clock configuration reference source");
- }
- _clock_ctrl->enable_external_ref(_clock_config.ref_source != clock_config_t::REF_INT);
- break;
-
- case usrp2_iface::USRP_NXXX: break;
- }
-
- //masters always drive the clock over serdes
- _clock_ctrl->enable_mimo_clock_out(_mimo_clocking_mode_is_master);
-
- //set the mimo clock delay over the serdes
- if (_mimo_clocking_mode_is_master){
- switch(_iface->get_rev()){
- case usrp2_iface::USRP_N200:
- case usrp2_iface::USRP_N210:
- case usrp2_iface::USRP_N200_R4:
- case usrp2_iface::USRP_N210_R4:
- _clock_ctrl->set_mimo_clock_delay(mimo_clock_delay_usrp_n2xx);
- break;
-
- case usrp2_iface::USRP2_REV4:
- _clock_ctrl->set_mimo_clock_delay(mimo_clock_delay_usrp2_rev4);
- break;
-
- default: break; //not handled
- }
- }
-
-}
-
-void usrp2_mboard_impl::set_time_spec(const time_spec_t &time_spec, bool now){
- //dont set the time for slave devices, they always take from mimo cable
- if (not _mimo_clocking_mode_is_master) return;
-
- //set the ticks
- _iface->poke32(U2_REG_TIME64_TICKS, time_spec.get_tick_count(get_master_clock_freq()));
-
- //set the flags register
- boost::uint32_t imm_flags = (now)? U2_FLAG_TIME64_LATCH_NOW : U2_FLAG_TIME64_LATCH_NEXT_PPS;
- _iface->poke32(U2_REG_TIME64_IMM, imm_flags);
-
- //set the seconds (latches in all 3 registers)
- _iface->poke32(U2_REG_TIME64_SECS, boost::uint32_t(time_spec.get_full_secs()));
-}
-
-/***********************************************************************
- * MBoard Get Properties
- **********************************************************************/
-static const std::string dboard_name = "0";
-
-void usrp2_mboard_impl::get(const wax::obj &key_, wax::obj &val){
- named_prop_t key = named_prop_t::extract(key_);
- //handle the get request conditioned on the key
- switch(key.as<mboard_prop_t>()){
- case MBOARD_PROP_NAME:
- val = _iface->get_cname() + " mboard";
- return;
-
- case MBOARD_PROP_OTHERS:
- val = prop_names_t();
- return;
-
- case MBOARD_PROP_RX_DBOARD:
- UHD_ASSERT_THROW(key.name == dboard_name);
- val = _rx_dboard_proxy->get_link();
- return;
-
- case MBOARD_PROP_RX_DBOARD_NAMES:
- val = prop_names_t(1, dboard_name);
- return;
-
- case MBOARD_PROP_TX_DBOARD:
- UHD_ASSERT_THROW(key.name == dboard_name);
- val = _tx_dboard_proxy->get_link();
- return;
-
- case MBOARD_PROP_TX_DBOARD_NAMES:
- val = prop_names_t(1, dboard_name);
- return;
-
- case MBOARD_PROP_RX_DSP:
- val = _rx_dsp_proxies[key.name]->get_link();
- return;
-
- case MBOARD_PROP_RX_DSP_NAMES:
- val = _rx_dsp_proxies.keys();
- return;
-
- case MBOARD_PROP_TX_DSP:
- val = _tx_dsp_proxies[key.name]->get_link();
- return;
-
- case MBOARD_PROP_TX_DSP_NAMES:
- val = _tx_dsp_proxies.keys();
- return;
-
- case MBOARD_PROP_CLOCK_CONFIG:
- val = _clock_config;
- return;
-
- case MBOARD_PROP_TIME_NOW: while(true){
- uint32_t secs = _iface->peek32(U2_REG_TIME64_SECS_RB_IMM);
- uint32_t ticks = _iface->peek32(U2_REG_TIME64_TICKS_RB_IMM);
- if (secs != _iface->peek32(U2_REG_TIME64_SECS_RB_IMM)) continue;
- val = time_spec_t(secs, ticks, get_master_clock_freq());
- return;
- }
-
- case MBOARD_PROP_TIME_PPS: while(true){
- uint32_t secs = _iface->peek32(U2_REG_TIME64_SECS_RB_PPS);
- uint32_t ticks = _iface->peek32(U2_REG_TIME64_TICKS_RB_PPS);
- if (secs != _iface->peek32(U2_REG_TIME64_SECS_RB_PPS)) continue;
- val = time_spec_t(secs, ticks, get_master_clock_freq());
- return;
- }
-
- case MBOARD_PROP_RX_SUBDEV_SPEC:
- val = _rx_subdev_spec;
- return;
-
- case MBOARD_PROP_TX_SUBDEV_SPEC:
- val = _tx_subdev_spec;
- return;
-
- case MBOARD_PROP_EEPROM_MAP:
- val = _iface->mb_eeprom;
- return;
-
- case MBOARD_PROP_CLOCK_RATE:
- val = this->get_master_clock_freq();
- return;
-
- case SUBDEV_PROP_SENSOR_NAMES:{
- prop_names_t names = boost::assign::list_of("mimo_locked")("ref_locked");
- if (_gps_ctrl.get()) {
- std::vector<std::string> gs = _gps_ctrl->get_sensors();
- names.insert(names.end(), gs.begin(), gs.end());
- }
- val = names;
- }
- return;
-
- case MBOARD_PROP_SENSOR:
- if(key.name == "mimo_locked") {
- val = sensor_value_t("MIMO", this->get_mimo_locked(), "locked", "unlocked");
- return;
- }
- else if(key.name == "ref_locked") {
- val = sensor_value_t("Ref", this->get_ref_locked(), "locked", "unlocked");
- return;
- }
- else if(uhd::has(_gps_ctrl->get_sensors(), key.name) and _gps_ctrl.get()) {
- val = _gps_ctrl->get_sensor(key.name);
- }
- else {
- UHD_THROW_PROP_GET_ERROR();
- }
- break;
-
- default: UHD_THROW_PROP_GET_ERROR();
- }
-}
-
-bool usrp2_mboard_impl::get_mimo_locked(void) {
- return bool((_iface->peek32(U2_REG_IRQ_RB) & (1<<10)) > 0);
-}
-
-bool usrp2_mboard_impl::get_ref_locked(void) {
- return bool((_iface->peek32(U2_REG_IRQ_RB) & (1<<11)) > 0);
-}
-
-/***********************************************************************
- * MBoard Set Properties
- **********************************************************************/
-void usrp2_mboard_impl::set(const wax::obj &key, const wax::obj &val){
- //handle the set request conditioned on the key
- switch(key.as<mboard_prop_t>()){
-
- case MBOARD_PROP_CLOCK_CONFIG:
- _clock_config = val.as<clock_config_t>();
- update_clock_config();
- return;
-
- case MBOARD_PROP_TIME_NOW:
- set_time_spec(val.as<time_spec_t>(), true);
- return;
-
- case MBOARD_PROP_TIME_PPS:
- set_time_spec(val.as<time_spec_t>(), false);
- return;
-
- case MBOARD_PROP_RX_SUBDEV_SPEC:
- _rx_subdev_spec = val.as<subdev_spec_t>();
- verify_rx_subdev_spec(_rx_subdev_spec, this->get_link());
- //sanity check
- UHD_ASSERT_THROW(_rx_subdev_spec.size() <= NUM_RX_DSPS);
- //set the mux
- for (size_t i = 0; i < _rx_subdev_spec.size(); i++){
- _iface->poke32(U2_REG_DSP_RX_MUX(i), dsp_type1::calc_rx_mux_word(
- _dboard_manager->get_rx_subdev(_rx_subdev_spec[i].sd_name)[SUBDEV_PROP_CONNECTION].as<subdev_conn_t>()
- ));
- }
- _device.update_xport_channel_mapping();
- return;
-
- case MBOARD_PROP_TX_SUBDEV_SPEC:
- _tx_subdev_spec = val.as<subdev_spec_t>();
- verify_tx_subdev_spec(_tx_subdev_spec, this->get_link());
- //sanity check
- UHD_ASSERT_THROW(_tx_subdev_spec.size() <= NUM_TX_DSPS);
- //set the mux
- for (size_t i = 0; i < _rx_subdev_spec.size(); i++){
- _iface->poke32(U2_REG_DSP_TX_MUX, dsp_type1::calc_tx_mux_word(
- _dboard_manager->get_tx_subdev(_tx_subdev_spec[i].sd_name)[SUBDEV_PROP_CONNECTION].as<subdev_conn_t>()
- ));
- }
- _device.update_xport_channel_mapping();
- return;
-
- case MBOARD_PROP_EEPROM_MAP:
- // Step1: commit the map, writing only those values set.
- // Step2: readback the entire eeprom map into the iface.
- val.as<mboard_eeprom_t>().commit(*_iface, mboard_eeprom_t::MAP_N100);
- _iface->mb_eeprom = mboard_eeprom_t(*_iface, mboard_eeprom_t::MAP_N100);
- return;
-
- case MBOARD_PROP_CLOCK_RATE:
- UHD_ASSERT_THROW(val.as<double>() == this->get_master_clock_freq());
- _device.update_xport_channel_mapping();
- 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 6ba364b28..aaa5acbd5 100644
--- a/host/lib/usrp/usrp2/usrp2_iface.cpp
+++ b/host/lib/usrp/usrp2/usrp2_iface.cpp
@@ -20,15 +20,15 @@
#include "usrp2_iface.hpp"
#include <uhd/exception.hpp>
#include <uhd/utils/msg.hpp>
+#include <uhd/utils/tasks.hpp>
#include <uhd/types/dict.hpp>
#include <boost/thread.hpp>
#include <boost/foreach.hpp>
#include <boost/asio.hpp> //used for htonl and ntohl
#include <boost/assign/list_of.hpp>
#include <boost/format.hpp>
+#include <boost/bind.hpp>
#include <boost/tokenizer.hpp>
-#include <boost/thread/thread.hpp>
-#include <boost/thread/barrier.hpp>
#include <boost/functional/hash.hpp>
#include <algorithm>
#include <iostream>
@@ -46,10 +46,6 @@ static const boost::uint32_t MIN_PROTO_COMPAT_I2C = 7;
static const boost::uint32_t MIN_PROTO_COMPAT_REG = USRP2_FW_COMPAT_NUM;
static const boost::uint32_t MIN_PROTO_COMPAT_UART = 7;
-// Map for virtual firmware regs (not very big so we can keep it here for now)
-#define U2_FW_REG_LOCK_TIME 0
-#define U2_FW_REG_LOCK_GPID 1
-
//Define get_gpid() to get a globally unique identifier for this process.
//The gpid is implemented as a hash of the pid and a unique machine identifier.
#ifdef UHD_PLATFORM_WIN32
@@ -110,13 +106,12 @@ public:
void lock_device(bool lock){
if (lock){
- boost::barrier spawn_barrier(2);
- _lock_thread_group.create_thread(boost::bind(&usrp2_iface_impl::lock_loop, this, boost::ref(spawn_barrier)));
- spawn_barrier.wait();
+ this->get_reg<boost::uint32_t, USRP2_REG_ACTION_FW_POKE32>(U2_FW_REG_LOCK_GPID, boost::uint32_t(get_gpid()));
+ _lock_task = task::make(boost::bind(&usrp2_iface_impl::lock_task, this));
}
else{
- _lock_thread_group.interrupt_all();
- _lock_thread_group.join_all();
+ _lock_task.reset(); //shutdown the task
+ this->get_reg<boost::uint32_t, USRP2_REG_ACTION_FW_POKE32>(U2_FW_REG_LOCK_TIME, 0); //unlock
}
}
@@ -132,52 +127,35 @@ public:
return lock_gpid != boost::uint32_t(get_gpid());
}
- void lock_loop(boost::barrier &spawn_barrier){
- spawn_barrier.wait();
-
- try{
- this->get_reg<boost::uint32_t, USRP2_REG_ACTION_FW_POKE32>(U2_FW_REG_LOCK_GPID, boost::uint32_t(get_gpid()));
- while(true){
- //re-lock in loop
- boost::uint32_t curr_secs = this->peek32(U2_REG_TIME64_SECS_RB_IMM);
- this->get_reg<boost::uint32_t, USRP2_REG_ACTION_FW_POKE32>(U2_FW_REG_LOCK_TIME, curr_secs);
- //sleep for a bit
- boost::this_thread::sleep(boost::posix_time::milliseconds(1500));
- }
- }
- catch(const boost::thread_interrupted &){
- this->get_reg<boost::uint32_t, USRP2_REG_ACTION_FW_POKE32>(U2_FW_REG_LOCK_TIME, 0); //unlock on exit
- }
- catch(const std::exception &e){
- UHD_MSG(error)
- << "An unexpected exception was caught in the locker loop." << std::endl
- << "The device will automatically unlock from this process." << std::endl
- << e.what() << std::endl
- ;
- }
+ void lock_task(void){
+ //re-lock in task
+ boost::uint32_t curr_secs = this->peek32(U2_REG_TIME64_SECS_RB_IMM);
+ this->get_reg<boost::uint32_t, USRP2_REG_ACTION_FW_POKE32>(U2_FW_REG_LOCK_TIME, curr_secs);
+ //sleep for a bit
+ boost::this_thread::sleep(boost::posix_time::milliseconds(1500));
}
/***********************************************************************
* Peek and Poke
**********************************************************************/
- void poke32(boost::uint32_t addr, boost::uint32_t data){
+ void poke32(wb_addr_type addr, boost::uint32_t data){
this->get_reg<boost::uint32_t, USRP2_REG_ACTION_FPGA_POKE32>(addr, data);
}
- boost::uint32_t peek32(boost::uint32_t addr){
+ boost::uint32_t peek32(wb_addr_type addr){
return this->get_reg<boost::uint32_t, USRP2_REG_ACTION_FPGA_PEEK32>(addr);
}
- void poke16(boost::uint32_t addr, boost::uint16_t data){
+ void poke16(wb_addr_type addr, boost::uint16_t data){
this->get_reg<boost::uint16_t, USRP2_REG_ACTION_FPGA_POKE16>(addr, data);
}
- boost::uint16_t peek16(boost::uint32_t addr){
+ boost::uint16_t peek16(wb_addr_type addr){
return this->get_reg<boost::uint16_t, USRP2_REG_ACTION_FPGA_PEEK16>(addr);
}
template <class T, usrp2_reg_action_t action>
- T get_reg(boost::uint32_t addr, T data = 0){
+ T get_reg(wb_addr_type addr, T data = 0){
//setup the out data
usrp2_ctrl_data_t out_data = usrp2_ctrl_data_t();
out_data.id = htonl(USRP2_CTRL_ID_GET_THIS_REGISTER_FOR_ME_BRO);
@@ -390,6 +368,11 @@ public:
UHD_THROW_INVALID_CODE_PATH();
}
+ const std::string get_fw_version_string(void){
+ boost::uint32_t minor = this->get_reg<boost::uint32_t, USRP2_REG_ACTION_FW_PEEK32>(U2_FW_REG_VER_MINOR);
+ return str(boost::format("%u.%u") % _protocol_compat % minor);
+ }
+
private:
//this lovely lady makes it all possible
udp_simple::sptr _ctrl_transport;
@@ -400,7 +383,7 @@ private:
boost::uint32_t _protocol_compat;
//lock thread stuff
- boost::thread_group _lock_thread_group;
+ task::sptr _lock_task;
};
/***********************************************************************
diff --git a/host/lib/usrp/usrp2/usrp2_iface.hpp b/host/lib/usrp/usrp2/usrp2_iface.hpp
index 16b640a70..b3c3ef4a2 100644
--- a/host/lib/usrp/usrp2/usrp2_iface.hpp
+++ b/host/lib/usrp/usrp2/usrp2_iface.hpp
@@ -19,15 +19,14 @@
#define INCLUDED_USRP2_IFACE_HPP
#include <uhd/transport/udp_simple.hpp>
-#include <uhd/usrp/mboard_iface.hpp>
+#include <uhd/types/serial.hpp>
+#include <uhd/usrp/mboard_eeprom.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/utility.hpp>
-#include <boost/cstdint.hpp>
#include <boost/function.hpp>
-#include <utility>
-#include <string>
#include "usrp2_regs.hpp"
-
+#include "wb_iface.hpp"
+#include <string>
//TODO: kill this crap when you have the top level GPS include file
typedef boost::function<void(std::string)> gps_send_fn_t;
@@ -38,7 +37,7 @@ typedef boost::function<std::string(void)> gps_recv_fn_t;
* Provides a set of functions to implementation layer.
* Including spi, peek, poke, control...
*/
-class usrp2_iface : public uhd::usrp::mboard_iface, boost::noncopyable{
+class usrp2_iface : public wb_iface, public uhd::spi_iface, public uhd::i2c_iface, public uhd::uart_iface{
public:
typedef boost::shared_ptr<usrp2_iface> sptr;
/*!
@@ -74,6 +73,9 @@ public:
//! Is this device locked?
virtual bool is_device_locked(void) = 0;
+ //! A version string for firmware
+ virtual const std::string get_fw_version_string(void) = 0;
+
//motherboard eeprom map structure
uhd::usrp::mboard_eeprom_t mb_eeprom;
};
diff --git a/host/lib/usrp/usrp2/usrp2_impl.cpp b/host/lib/usrp/usrp2/usrp2_impl.cpp
index aa584ac8b..45db0d081 100644
--- a/host/lib/usrp/usrp2/usrp2_impl.cpp
+++ b/host/lib/usrp/usrp2/usrp2_impl.cpp
@@ -22,18 +22,18 @@
#include <uhd/exception.hpp>
#include <uhd/transport/if_addrs.hpp>
#include <uhd/transport/udp_zero_copy.hpp>
-#include <uhd/usrp/device_props.hpp>
+#include <uhd/types/ranges.hpp>
#include <uhd/exception.hpp>
#include <uhd/utils/static.hpp>
#include <uhd/utils/byteswap.hpp>
-#include <boost/assign/list_of.hpp>
+#include <uhd/utils/safe_call.hpp>
#include <boost/format.hpp>
#include <boost/foreach.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/bind.hpp>
+#include <boost/assign/list_of.hpp>
#include <boost/asio/ip/address_v4.hpp>
#include <boost/asio.hpp> //used for htonl and ntohl
-#include <vector>
using namespace uhd;
using namespace uhd::usrp;
@@ -227,6 +227,40 @@ static mtu_result_t determine_mtu(const std::string &addr, const mtu_result_t &u
}
/***********************************************************************
+ * Helpers
+ **********************************************************************/
+static zero_copy_if::sptr make_xport(
+ const std::string &addr,
+ const std::string &port,
+ const device_addr_t &hints,
+ const std::string &filter
+){
+
+ //only copy hints that contain the filter word
+ device_addr_t filtered_hints;
+ BOOST_FOREACH(const std::string &key, hints.keys()){
+ if (key.find(filter) == std::string::npos) continue;
+ filtered_hints[key] = hints[key];
+ }
+
+ //make the transport object with the filtered hints
+ zero_copy_if::sptr xport = udp_zero_copy::make(addr, port, filtered_hints);
+
+ //Send a small data packet so the usrp2 knows the udp source port.
+ //This setup must happen before further initialization occurs
+ //or the async update packets will cause ICMP destination unreachable.
+ static const boost::uint32_t data[2] = {
+ uhd::htonx(boost::uint32_t(0 /* don't care seq num */)),
+ uhd::htonx(boost::uint32_t(USRP2_INVALID_VRT_HEADER))
+ };
+ transport::managed_send_buffer::sptr send_buff = xport->get_send_buff();
+ std::memcpy(send_buff->cast<void*>(), &data, sizeof(data));
+ send_buff->commit(sizeof(data));
+
+ return xport;
+}
+
+/***********************************************************************
* Structors
**********************************************************************/
usrp2_impl::usrp2_impl(const device_addr_t &_device_addr){
@@ -272,67 +306,405 @@ usrp2_impl::usrp2_impl(const device_addr_t &_device_addr){
device_args = separate_device_addr(device_addr); //update args for new frame sizes
- //setup rx otw type
- _rx_otw_type.width = 16;
- _rx_otw_type.shift = 0;
- _rx_otw_type.byteorder = uhd::otw_type_t::BO_BIG_ENDIAN;
-
- //setup tx otw type
- _tx_otw_type.width = 16;
- _tx_otw_type.shift = 0;
- _tx_otw_type.byteorder = uhd::otw_type_t::BO_BIG_ENDIAN;
+ ////////////////////////////////////////////////////////////////////
+ // create controller objects and initialize the properties tree
+ ////////////////////////////////////////////////////////////////////
+ _tree = property_tree::make();
+ _tree->create<std::string>("/name").set("USRP2 / N-Series Device");
+
+ for (size_t mbi = 0; mbi < device_args.size(); mbi++){
+ const device_addr_t device_args_i = device_args[mbi];
+ const std::string mb = boost::lexical_cast<std::string>(mbi);
+ const std::string addr = device_args_i["addr"];
+ const property_tree::path_type mb_path = "/mboards/" + mb;
+
+ ////////////////////////////////////////////////////////////////
+ // create the iface that controls i2c, spi, uart, and wb
+ ////////////////////////////////////////////////////////////////
+ _mbc[mb].iface = usrp2_iface::make(udp_simple::make_connected(
+ addr, BOOST_STRINGIZE(USRP2_UDP_CTRL_PORT)
+ ));
+ _tree->create<std::string>(mb_path / "name").set(_mbc[mb].iface->get_cname());
+ _tree->create<std::string>(mb_path / "fw_version").set(_mbc[mb].iface->get_fw_version_string());
+
+ //check the fpga compatibility number
+ const boost::uint32_t fpga_compat_num = _mbc[mb].iface->peek32(U2_REG_COMPAT_NUM_RB);
+ boost::uint16_t fpga_major = fpga_compat_num >> 16, fpga_minor = fpga_compat_num & 0xffff;
+ if (fpga_major == 0){ //old version scheme
+ fpga_major = fpga_minor;
+ fpga_minor = 0;
+ }
+ if (fpga_major != USRP2_FPGA_COMPAT_NUM){
+ throw uhd::runtime_error(str(boost::format(
+ "\nPlease update the firmware and FPGA images for your device.\n"
+ "See the application notes for USRP2/N-Series for instructions.\n"
+ "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_major));
+ }
+ _tree->create<std::string>(mb_path / "fpga_version").set(str(boost::format("%u.%u") % fpga_major % fpga_minor));
- //!!!!! set the otw type here before continuing, its used below
+ //lock the device/motherboard to this process
+ _mbc[mb].iface->lock_device(true);
- //create a new mboard handler for each control transport
- for(size_t i = 0; i < device_args.size(); i++){
- device_addr_t dev_addr_i = device_args[i];
- BOOST_FOREACH(const std::string &key, device_addr.keys()){
- if (dev_addr_i.has_key(key)) continue;
- dev_addr_i[key] = device_addr[key];
+ ////////////////////////////////////////////////////////////////
+ // construct transports for RX and TX DSPs
+ ////////////////////////////////////////////////////////////////
+ UHD_LOG << "Making transport for RX DSP0..." << std::endl;
+ _mbc[mb].rx_dsp_xports.push_back(make_xport(
+ addr, BOOST_STRINGIZE(USRP2_UDP_RX_DSP0_PORT), device_args_i, "recv"
+ ));
+ UHD_LOG << "Making transport for RX DSP1..." << std::endl;
+ _mbc[mb].rx_dsp_xports.push_back(make_xport(
+ addr, BOOST_STRINGIZE(USRP2_UDP_RX_DSP1_PORT), device_args_i, "recv"
+ ));
+ UHD_LOG << "Making transport for TX DSP0..." << std::endl;
+ _mbc[mb].tx_dsp_xport = make_xport(
+ addr, BOOST_STRINGIZE(USRP2_UDP_TX_DSP0_PORT), device_args_i, "send"
+ );
+ //set the filter on the router to take dsp data from this port
+ _mbc[mb].iface->poke32(U2_REG_ROUTER_CTRL_PORTS, USRP2_UDP_TX_DSP0_PORT);
+
+ ////////////////////////////////////////////////////////////////
+ // setup the mboard eeprom
+ ////////////////////////////////////////////////////////////////
+ _tree->create<mboard_eeprom_t>(mb_path / "eeprom")
+ .set(_mbc[mb].iface->mb_eeprom)
+ .subscribe(boost::bind(&usrp2_impl::set_mb_eeprom, this, mb, _1));
+
+ ////////////////////////////////////////////////////////////////
+ // create clock control objects
+ ////////////////////////////////////////////////////////////////
+ _mbc[mb].clock = usrp2_clock_ctrl::make(_mbc[mb].iface);
+ _tree->create<double>(mb_path / "tick_rate")
+ .publish(boost::bind(&usrp2_clock_ctrl::get_master_clock_rate, _mbc[mb].clock))
+ .subscribe(boost::bind(&usrp2_impl::update_tick_rate, this, _1));
+
+ ////////////////////////////////////////////////////////////////
+ // create codec control objects
+ ////////////////////////////////////////////////////////////////
+ const property_tree::path_type rx_codec_path = mb_path / "rx_codecs/A";
+ const property_tree::path_type tx_codec_path = mb_path / "tx_codecs/A";
+ _tree->create<int>(rx_codec_path / "gains"); //phony property so this dir exists
+ _tree->create<int>(tx_codec_path / "gains"); //phony property so this dir exists
+ _mbc[mb].codec = usrp2_codec_ctrl::make(_mbc[mb].iface);
+ switch(_mbc[mb].iface->get_rev()){
+ case usrp2_iface::USRP_N200:
+ case usrp2_iface::USRP_N210:
+ case usrp2_iface::USRP_N200_R4:
+ case usrp2_iface::USRP_N210_R4:{
+ _tree->create<std::string>(rx_codec_path / "name").set("ads62p44");
+ _tree->create<meta_range_t>(rx_codec_path / "gains/digital/range").set(meta_range_t(0, 6.0, 0.5));
+ _tree->create<double>(rx_codec_path / "gains/digital/value")
+ .subscribe(boost::bind(&usrp2_codec_ctrl::set_rx_digital_gain, _mbc[mb].codec, _1)).set(0);
+ _tree->create<meta_range_t>(rx_codec_path / "gains/fine/range").set(meta_range_t(0, 0.5, 0.05));
+ _tree->create<double>(rx_codec_path / "gains/fine/value")
+ .subscribe(boost::bind(&usrp2_codec_ctrl::set_rx_digital_fine_gain, _mbc[mb].codec, _1)).set(0);
+ }break;
+
+ case usrp2_iface::USRP2_REV3:
+ case usrp2_iface::USRP2_REV4:
+ _tree->create<std::string>(rx_codec_path / "name").set("ltc2284");
+ break;
+
+ case usrp2_iface::USRP_NXXX:
+ _tree->create<std::string>(rx_codec_path / "name").set("??????");
+ break;
}
- _mboards.push_back(usrp2_mboard_impl::sptr(
- new usrp2_mboard_impl(dev_addr_i, i, *this)
+ _tree->create<std::string>(tx_codec_path / "name").set("ad9777");
+
+ ////////////////////////////////////////////////////////////////
+ // create gpsdo control objects
+ ////////////////////////////////////////////////////////////////
+ if (_mbc[mb].iface->mb_eeprom["gpsdo"] == "internal"){
+ _mbc[mb].gps = gps_ctrl::make(
+ _mbc[mb].iface->get_gps_write_fn(),
+ _mbc[mb].iface->get_gps_read_fn()
+ );
+ BOOST_FOREACH(const std::string &name, _mbc[mb].gps->get_sensors()){
+ _tree->create<sensor_value_t>(mb_path / "sensors" / name)
+ .publish(boost::bind(&gps_ctrl::get_sensor, _mbc[mb].gps, name));
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////
+ // and do the misc mboard sensors
+ ////////////////////////////////////////////////////////////////
+ _tree->create<sensor_value_t>(mb_path / "sensors/mimo_locked")
+ .publish(boost::bind(&usrp2_impl::get_mimo_locked, this, mb));
+ _tree->create<sensor_value_t>(mb_path / "sensors/ref_locked")
+ .publish(boost::bind(&usrp2_impl::get_ref_locked, this, mb));
+
+ ////////////////////////////////////////////////////////////////
+ // create frontend control objects
+ ////////////////////////////////////////////////////////////////
+ _mbc[mb].rx_fe = rx_frontend_core_200::make(
+ _mbc[mb].iface, U2_REG_SR_ADDR(SR_RX_FRONT)
+ );
+ _mbc[mb].tx_fe = tx_frontend_core_200::make(
+ _mbc[mb].iface, U2_REG_SR_ADDR(SR_TX_FRONT)
+ );
+ //TODO lots of properties to expose here for frontends
+ _tree->create<subdev_spec_t>(mb_path / "rx_subdev_spec")
+ .coerce(boost::bind(&usrp2_impl::update_rx_subdev_spec, this, mb, _1));
+ _tree->create<subdev_spec_t>(mb_path / "tx_subdev_spec")
+ .coerce(boost::bind(&usrp2_impl::update_tx_subdev_spec, this, mb, _1));
+
+ ////////////////////////////////////////////////////////////////
+ // create rx dsp control objects
+ ////////////////////////////////////////////////////////////////
+ _mbc[mb].rx_dsps.push_back(rx_dsp_core_200::make(
+ _mbc[mb].iface, U2_REG_SR_ADDR(SR_RX_DSP0), U2_REG_SR_ADDR(SR_RX_CTRL0), USRP2_RX_SID_BASE + 0, true
));
- //use an empty name when there is only one mboard
- std::string name = (device_args.size() > 1)? boost::lexical_cast<std::string>(i) : "";
- _mboard_dict[name] = _mboards.back();
+ _mbc[mb].rx_dsps.push_back(rx_dsp_core_200::make(
+ _mbc[mb].iface, U2_REG_SR_ADDR(SR_RX_DSP1), U2_REG_SR_ADDR(SR_RX_CTRL1), USRP2_RX_SID_BASE + 1, true
+ ));
+ for (size_t dspno = 0; dspno < _mbc[mb].rx_dsps.size(); dspno++){
+ _mbc[mb].rx_dsps[dspno]->set_link_rate(USRP2_LINK_RATE_BPS);
+ _tree->access<double>(mb_path / "tick_rate")
+ .subscribe(boost::bind(&rx_dsp_core_200::set_tick_rate, _mbc[mb].rx_dsps[dspno], _1));
+ //This is a hack/fix for the lingering packet problem.
+ //The dsp core starts streaming briefly... now we flush
+ _mbc[mb].rx_dsp_xports[dspno]->get_recv_buff(0.01).get(); //recv with timeout for lingering
+ _mbc[mb].rx_dsp_xports[dspno]->get_recv_buff(0.01).get(); //recv with timeout for expected
+ property_tree::path_type rx_dsp_path = mb_path / str(boost::format("rx_dsps/%u") % dspno);
+ _tree->create<double>(rx_dsp_path / "rate/value")
+ .coerce(boost::bind(&rx_dsp_core_200::set_host_rate, _mbc[mb].rx_dsps[dspno], _1))
+ .subscribe(boost::bind(&usrp2_impl::update_rx_samp_rate, this, _1));
+ _tree->create<double>(rx_dsp_path / "freq/value")
+ .coerce(boost::bind(&rx_dsp_core_200::set_freq, _mbc[mb].rx_dsps[dspno], _1));
+ _tree->create<meta_range_t>(rx_dsp_path / "freq/range")
+ .publish(boost::bind(&rx_dsp_core_200::get_freq_range, _mbc[mb].rx_dsps[dspno]));
+ _tree->create<stream_cmd_t>(rx_dsp_path / "stream_cmd")
+ .subscribe(boost::bind(&rx_dsp_core_200::issue_stream_command, _mbc[mb].rx_dsps[dspno], _1));
+ }
+
+ ////////////////////////////////////////////////////////////////
+ // create tx dsp control objects
+ ////////////////////////////////////////////////////////////////
+ _mbc[mb].tx_dsp = tx_dsp_core_200::make(
+ _mbc[mb].iface, U2_REG_SR_ADDR(SR_TX_DSP), U2_REG_SR_ADDR(SR_TX_CTRL), USRP2_TX_ASYNC_SID
+ );
+ _mbc[mb].tx_dsp->set_link_rate(USRP2_LINK_RATE_BPS);
+ _tree->access<double>(mb_path / "tick_rate")
+ .subscribe(boost::bind(&tx_dsp_core_200::set_tick_rate, _mbc[mb].tx_dsp, _1));
+ _tree->create<double>(mb_path / "tx_dsps/0/rate/value")
+ .coerce(boost::bind(&tx_dsp_core_200::set_host_rate, _mbc[mb].tx_dsp, _1))
+ .subscribe(boost::bind(&usrp2_impl::update_tx_samp_rate, this, _1));
+ _tree->create<double>(mb_path / "tx_dsps/0/freq/value")
+ .coerce(boost::bind(&usrp2_impl::set_tx_dsp_freq, this, mb, _1));
+ _tree->create<meta_range_t>(mb_path / "tx_dsps/0/freq/range")
+ .publish(boost::bind(&usrp2_impl::get_tx_dsp_freq_range, this, mb));
+
+ //setup dsp flow control
+ const double ups_per_sec = device_args_i.cast<double>("ups_per_sec", 20);
+ const size_t send_frame_size = _mbc[mb].tx_dsp_xport->get_send_frame_size();
+ const double ups_per_fifo = device_args_i.cast<double>("ups_per_fifo", 8.0);
+ _mbc[mb].tx_dsp->set_updates(
+ (ups_per_sec > 0.0)? size_t(100e6/*approx tick rate*//ups_per_sec) : 0,
+ (ups_per_fifo > 0.0)? size_t(USRP2_SRAM_BYTES/ups_per_fifo/send_frame_size) : 0
+ );
+
+ ////////////////////////////////////////////////////////////////
+ // create time control objects
+ ////////////////////////////////////////////////////////////////
+ time64_core_200::readback_bases_type time64_rb_bases;
+ time64_rb_bases.rb_secs_now = U2_REG_TIME64_SECS_RB_IMM;
+ time64_rb_bases.rb_ticks_now = U2_REG_TIME64_TICKS_RB_IMM;
+ time64_rb_bases.rb_secs_pps = U2_REG_TIME64_SECS_RB_PPS;
+ time64_rb_bases.rb_ticks_pps = U2_REG_TIME64_TICKS_RB_PPS;
+ _mbc[mb].time64 = time64_core_200::make(
+ _mbc[mb].iface, U2_REG_SR_ADDR(SR_TIME64), time64_rb_bases, mimo_clock_sync_delay_cycles
+ );
+ _tree->access<double>(mb_path / "tick_rate")
+ .subscribe(boost::bind(&time64_core_200::set_tick_rate, _mbc[mb].time64, _1));
+ _tree->create<time_spec_t>(mb_path / "time/now")
+ .publish(boost::bind(&time64_core_200::get_time_now, _mbc[mb].time64))
+ .subscribe(boost::bind(&time64_core_200::set_time_now, _mbc[mb].time64, _1));
+ _tree->create<time_spec_t>(mb_path / "time/pps")
+ .publish(boost::bind(&time64_core_200::get_time_last_pps, _mbc[mb].time64))
+ .subscribe(boost::bind(&time64_core_200::set_time_next_pps, _mbc[mb].time64, _1));
+ //setup time source props
+ _tree->create<std::string>(mb_path / "time_source/value")
+ .subscribe(boost::bind(&time64_core_200::set_time_source, _mbc[mb].time64, _1));
+ _tree->create<std::vector<std::string> >(mb_path / "time_source/options")
+ .publish(boost::bind(&time64_core_200::get_time_sources, _mbc[mb].time64));
+ //setup reference source props
+ _tree->create<std::string>(mb_path / "clock_source/value")
+ .subscribe(boost::bind(&usrp2_impl::update_clock_source, this, mb, _1));
+ static const std::vector<std::string> clock_sources = boost::assign::list_of("internal")("external")("mimo");
+ _tree->create<std::vector<std::string> >(mb_path / "clock_source/options").set(clock_sources);
+
+ ////////////////////////////////////////////////////////////////
+ // create dboard control objects
+ ////////////////////////////////////////////////////////////////
+
+ //read the dboard eeprom to extract the dboard ids
+ dboard_eeprom_t rx_db_eeprom, tx_db_eeprom, gdb_eeprom;
+ rx_db_eeprom.load(*_mbc[mb].iface, USRP2_I2C_ADDR_RX_DB);
+ tx_db_eeprom.load(*_mbc[mb].iface, USRP2_I2C_ADDR_TX_DB);
+ gdb_eeprom.load(*_mbc[mb].iface, USRP2_I2C_ADDR_TX_DB ^ 5);
+
+ //create the properties and register subscribers
+ _tree->create<dboard_eeprom_t>(mb_path / "dboards/A/rx_eeprom")
+ .set(rx_db_eeprom)
+ .subscribe(boost::bind(&usrp2_impl::set_db_eeprom, this, mb, "rx", _1));
+ _tree->create<dboard_eeprom_t>(mb_path / "dboards/A/tx_eeprom")
+ .set(tx_db_eeprom)
+ .subscribe(boost::bind(&usrp2_impl::set_db_eeprom, this, mb, "tx", _1));
+ _tree->create<dboard_eeprom_t>(mb_path / "dboards/A/gdb_eeprom")
+ .set(gdb_eeprom)
+ .subscribe(boost::bind(&usrp2_impl::set_db_eeprom, this, mb, "gdb", _1));
+
+ //create a new dboard interface and manager
+ _mbc[mb].dboard_iface = make_usrp2_dboard_iface(_mbc[mb].iface, _mbc[mb].clock);
+ _tree->create<dboard_iface::sptr>(mb_path / "dboards/A/iface").set(_mbc[mb].dboard_iface);
+ _mbc[mb].dboard_manager = dboard_manager::make(
+ rx_db_eeprom.id,
+ ((gdb_eeprom.id == dboard_id_t::none())? tx_db_eeprom : gdb_eeprom).id,
+ _mbc[mb].dboard_iface
+ );
+ BOOST_FOREACH(const std::string &name, _mbc[mb].dboard_manager->get_rx_subdev_names()){
+ dboard_manager::populate_prop_tree_from_subdev(
+ _tree->subtree(mb_path / "dboards/A/rx_frontends" / name),
+ _mbc[mb].dboard_manager->get_rx_subdev(name)
+ );
+ }
+ BOOST_FOREACH(const std::string &name, _mbc[mb].dboard_manager->get_tx_subdev_names()){
+ dboard_manager::populate_prop_tree_from_subdev(
+ _tree->subtree(mb_path / "dboards/A/tx_frontends" / name),
+ _mbc[mb].dboard_manager->get_tx_subdev(name)
+ );
+ }
}
- //init the send and recv io
- io_init();
+ //initialize io handling
+ this->io_init();
+
+ //do some post-init tasks
+ BOOST_FOREACH(const std::string &mb, _mbc.keys()){
+ property_tree::path_type root = "/mboards/" + mb;
+ _tree->access<double>(root / "tick_rate").update();
+
+ //and now that the tick rate is set, init the host rates to something
+ BOOST_FOREACH(const std::string &name, _tree->list(root / "rx_dsps")){
+ _tree->access<double>(root / "rx_dsps" / name / "rate" / "value").set(1e6);
+ }
+ BOOST_FOREACH(const std::string &name, _tree->list(root / "tx_dsps")){
+ _tree->access<double>(root / "tx_dsps" / name / "rate" / "value").set(1e6);
+ }
+
+ _tree->access<subdev_spec_t>(root / "rx_subdev_spec").set(subdev_spec_t("A:"+_mbc[mb].dboard_manager->get_rx_subdev_names()[0]));
+ _tree->access<subdev_spec_t>(root / "tx_subdev_spec").set(subdev_spec_t("A:"+_mbc[mb].dboard_manager->get_tx_subdev_names()[0]));
+ _tree->access<std::string>(root / "clock_source/value").set("internal");
+ _tree->access<std::string>(root / "time_source/value").set("none");
+
+ //GPS installed: use external ref, time, and init time spec
+ if (_mbc[mb].gps.get() != NULL){
+ _tree->access<std::string>(root / "time_source/value").set("external");
+ _tree->access<std::string>(root / "clock_source/value").set("external");
+ _mbc[mb].time64->set_time_next_pps(time_spec_t(time_t(_mbc[mb].gps->get_sensor("gps_time").to_int()+1)));
+ }
+ }
}
-usrp2_impl::~usrp2_impl(void){
- /* NOP */
+usrp2_impl::~usrp2_impl(void){UHD_SAFE_CALL(
+ BOOST_FOREACH(const std::string &mb, _mbc.keys()){
+ _mbc[mb].tx_dsp->set_updates(0, 0);
+ }
+)}
+
+void usrp2_impl::set_mb_eeprom(const std::string &mb, const uhd::usrp::mboard_eeprom_t &mb_eeprom){
+ mb_eeprom.commit(*(_mbc[mb].iface), mboard_eeprom_t::MAP_N100);
}
-/***********************************************************************
- * Device Properties
- **********************************************************************/
-void usrp2_impl::get(const wax::obj &key_, wax::obj &val){
- named_prop_t key = named_prop_t::extract(key_);
+void usrp2_impl::set_db_eeprom(const std::string &mb, const std::string &type, const uhd::usrp::dboard_eeprom_t &db_eeprom){
+ if (type == "rx") db_eeprom.store(*_mbc[mb].iface, USRP2_I2C_ADDR_RX_DB);
+ if (type == "tx") db_eeprom.store(*_mbc[mb].iface, USRP2_I2C_ADDR_TX_DB);
+ if (type == "gdb") db_eeprom.store(*_mbc[mb].iface, USRP2_I2C_ADDR_TX_DB ^ 5);
+}
+
+sensor_value_t usrp2_impl::get_mimo_locked(const std::string &mb){
+ const bool lock = (_mbc[mb].iface->peek32(U2_REG_IRQ_RB) & (1<<10)) != 0;
+ return sensor_value_t("MIMO", lock, "locked", "unlocked");
+}
- //handle the get request conditioned on the key
- switch(key.as<device_prop_t>()){
- case DEVICE_PROP_NAME:
- if (_mboards.size() > 1) val = std::string("USRP2/N Series multi-device");
- else val = std::string("USRP2/N Series device");
- return;
+sensor_value_t usrp2_impl::get_ref_locked(const std::string &mb){
+ const bool lock = (_mbc[mb].iface->peek32(U2_REG_IRQ_RB) & (1<<11)) != 0;
+ return sensor_value_t("Ref", lock, "locked", "unlocked");
+}
- case DEVICE_PROP_MBOARD:
- val = _mboard_dict[key.name]->get_link();
- return;
+#include <boost/math/special_functions/round.hpp>
+#include <boost/math/special_functions/sign.hpp>
- case DEVICE_PROP_MBOARD_NAMES:
- val = prop_names_t(_mboard_dict.keys());
- return;
+double usrp2_impl::set_tx_dsp_freq(const std::string &mb, const double freq_){
+ double new_freq = freq_;
+ const double tick_rate = _tree->access<double>("/mboards/"+mb+"/tick_rate").get();
- default: UHD_THROW_PROP_GET_ERROR();
- }
+ //calculate the DAC shift (multiples of rate)
+ const int sign = boost::math::sign(new_freq);
+ const int zone = std::min(boost::math::iround(new_freq/tick_rate), 2);
+ const double dac_shift = sign*zone*tick_rate;
+ new_freq -= dac_shift; //update FPGA DSP target freq
+
+ //set the DAC shift (modulation mode)
+ if (zone == 0) _mbc[mb].codec->set_tx_mod_mode(0); //no shift
+ else _mbc[mb].codec->set_tx_mod_mode(sign*4/zone); //DAC interp = 4
+
+ return _mbc[mb].tx_dsp->set_freq(new_freq) + dac_shift; //actual freq
}
-void usrp2_impl::set(const wax::obj &, const wax::obj &){
- UHD_THROW_PROP_SET_ERROR();
+meta_range_t usrp2_impl::get_tx_dsp_freq_range(const std::string &mb){
+ const double tick_rate = _tree->access<double>("/mboards/"+mb+"/tick_rate").get();
+ const meta_range_t dsp_range = _mbc[mb].tx_dsp->get_freq_range();
+ return meta_range_t(dsp_range.start() - tick_rate*2, dsp_range.stop() + tick_rate*2, dsp_range.step());
+}
+
+void usrp2_impl::update_clock_source(const std::string &mb, const std::string &source){
+ //clock source ref 10mhz
+ switch(_mbc[mb].iface->get_rev()){
+ case usrp2_iface::USRP_N200:
+ case usrp2_iface::USRP_N210:
+ case usrp2_iface::USRP_N200_R4:
+ case usrp2_iface::USRP_N210_R4:
+ if (source == "internal") _mbc[mb].iface->poke32(U2_REG_MISC_CTRL_CLOCK, 0x12);
+ else if (source == "external") _mbc[mb].iface->poke32(U2_REG_MISC_CTRL_CLOCK, 0x1C);
+ else if (source == "mimo") _mbc[mb].iface->poke32(U2_REG_MISC_CTRL_CLOCK, 0x15);
+ else throw uhd::value_error("unhandled clock configuration reference source: " + source);
+ _mbc[mb].clock->enable_external_ref(true); //USRP2P has an internal 10MHz TCXO
+ break;
+
+ case usrp2_iface::USRP2_REV3:
+ case usrp2_iface::USRP2_REV4:
+ if (source == "internal") _mbc[mb].iface->poke32(U2_REG_MISC_CTRL_CLOCK, 0x10);
+ else if (source == "external") _mbc[mb].iface->poke32(U2_REG_MISC_CTRL_CLOCK, 0x1C);
+ else if (source == "mimo") _mbc[mb].iface->poke32(U2_REG_MISC_CTRL_CLOCK, 0x15);
+ else throw uhd::value_error("unhandled clock configuration reference source: " + source);
+ _mbc[mb].clock->enable_external_ref(source != "internal");
+ break;
+
+ case usrp2_iface::USRP_NXXX: break;
+ }
+
+ //always drive the clock over serdes if not locking to it
+ _mbc[mb].clock->enable_mimo_clock_out(source != "mimo");
+
+ //set the mimo clock delay over the serdes
+ if (source != "mimo"){
+ switch(_mbc[mb].iface->get_rev()){
+ case usrp2_iface::USRP_N200:
+ case usrp2_iface::USRP_N210:
+ case usrp2_iface::USRP_N200_R4:
+ case usrp2_iface::USRP_N210_R4:
+ _mbc[mb].clock->set_mimo_clock_delay(mimo_clock_delay_usrp_n2xx);
+ break;
+
+ case usrp2_iface::USRP2_REV4:
+ _mbc[mb].clock->set_mimo_clock_delay(mimo_clock_delay_usrp2_rev4);
+ break;
+
+ default: break; //not handled
+ }
+ }
}
diff --git a/host/lib/usrp/usrp2/usrp2_impl.hpp b/host/lib/usrp/usrp2/usrp2_impl.hpp
index 4d19863b1..644eab824 100644
--- a/host/lib/usrp/usrp2/usrp2_impl.hpp
+++ b/host/lib/usrp/usrp2/usrp2_impl.hpp
@@ -21,6 +21,12 @@
#include "usrp2_iface.hpp"
#include "clock_ctrl.hpp"
#include "codec_ctrl.hpp"
+#include "rx_frontend_core_200.hpp"
+#include "tx_frontend_core_200.hpp"
+#include "rx_dsp_core_200.hpp"
+#include "tx_dsp_core_200.hpp"
+#include "time64_core_200.hpp"
+#include <uhd/property_tree.hpp>
#include <uhd/usrp/gps_ctrl.hpp>
#include <uhd/device.hpp>
#include <uhd/utils/pimpl.hpp>
@@ -37,6 +43,14 @@
#include <uhd/usrp/dboard_manager.hpp>
#include <uhd/usrp/subdev_spec.hpp>
+static const double USRP2_LINK_RATE_BPS = 1000e6/8;
+static const double mimo_clock_delay_usrp2_rev4 = 4.18e-9;
+static const double mimo_clock_delay_usrp_n2xx = 3.55e-9;
+static const size_t mimo_clock_sync_delay_cycles = 137;
+static const size_t USRP2_SRAM_BYTES = size_t(1 << 20);
+static const boost::uint32_t USRP2_TX_ASYNC_SID = 2;
+static const boost::uint32_t USRP2_RX_SID_BASE = 3;
+
/*!
* Make a usrp2 dboard interface.
* \param iface the usrp2 interface object
@@ -49,139 +63,13 @@ uhd::usrp::dboard_iface::sptr make_usrp2_dboard_iface(
);
/*!
- * Simple wax obj proxy class:
- * Provides a wax obj interface for a set and a get function.
- * This allows us to create nested properties structures
- * while maintaining flattened code within the implementation.
- */
-class wax_obj_proxy : public wax::obj{
-public:
- typedef boost::function<void(const wax::obj &, wax::obj &)> get_t;
- typedef boost::function<void(const wax::obj &, const wax::obj &)> set_t;
- typedef boost::shared_ptr<wax_obj_proxy> sptr;
-
- static sptr make(const get_t &get, const set_t &set){
- return sptr(new wax_obj_proxy(get, set));
- }
-
-private:
- get_t _get; set_t _set;
- wax_obj_proxy(const get_t &get, const set_t &set): _get(get), _set(set){};
- void get(const wax::obj &key, wax::obj &val){return _get(key, val);}
- void set(const wax::obj &key, const wax::obj &val){return _set(key, val);}
-};
-
-class usrp2_impl;
-
-/*!
- * USRP2 mboard implementation guts:
- * The implementation details are encapsulated here.
- * Handles properties on the mboard, dboard, dsps...
- */
-class usrp2_mboard_impl : public wax::obj{
-public:
- typedef boost::shared_ptr<usrp2_mboard_impl> sptr;
-
- static const size_t NUM_RX_DSPS = 2;
- static const size_t NUM_TX_DSPS = 1;
- static const size_t MAX_NUM_DSPS = 2;
-
- //structors
- usrp2_mboard_impl(
- const uhd::device_addr_t &device_addr,
- size_t index, usrp2_impl &device
- );
- ~usrp2_mboard_impl(void);
-
- inline double get_master_clock_freq(void){
- return _clock_ctrl->get_master_clock_rate();
- }
-
- void handle_overflow(size_t);
-
-private:
- size_t _index;
- usrp2_impl &_device;
- bool _mimo_clocking_mode_is_master;
-
- //interfaces
- usrp2_iface::sptr _iface;
- usrp2_clock_ctrl::sptr _clock_ctrl;
- usrp2_codec_ctrl::sptr _codec_ctrl;
- gps_ctrl::sptr _gps_ctrl;
-
- //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;
-
- //rx and tx dboard methods and objects
- uhd::usrp::dboard_manager::sptr _dboard_manager;
- uhd::usrp::dboard_iface::sptr _dboard_iface;
- void dboard_init(void);
-
- //methods and shadows for clock configuration
- uhd::clock_config_t _clock_config;
- 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;
-
- void rx_codec_set_gain(double, const std::string &);
- uhd::dict<std::string, double> _codec_rx_gains;
-
- //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::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::usrp::dboard_eeprom_t _tx_db_eeprom, _gdb_eeprom;
-
- //methods and shadows for the dsps
- UHD_PIMPL_DECL(dsp_impl) _dsp_impl;
- void dsp_init(void);
- void issue_ddc_stream_cmd(const uhd::stream_cmd_t &, size_t);
-
- //properties interface for ddc
- void ddc_get(const wax::obj &, wax::obj &, size_t);
- void ddc_set(const wax::obj &, const wax::obj &, size_t);
- uhd::dict<std::string, wax_obj_proxy::sptr> _rx_dsp_proxies;
-
- //properties interface for duc
- void duc_get(const wax::obj &, wax::obj &, size_t);
- void duc_set(const wax::obj &, const wax::obj &, size_t);
- uhd::dict<std::string, wax_obj_proxy::sptr> _tx_dsp_proxies;
-
- //sensors methods for mboard
- bool get_mimo_locked(void);
- bool get_ref_locked(void);
-};
-
-/*!
* USRP2 implementation guts:
* The implementation details are encapsulated here.
* Handles device properties and streaming...
*/
class usrp2_impl : public uhd::device{
public:
- static const size_t sram_bytes = size_t(1 << 20);
- static const boost::uint32_t RECV_SID = 1;
- static const boost::uint32_t ASYNC_SID = 2;
-
usrp2_impl(const uhd::device_addr_t &);
-
~usrp2_impl(void);
//the io interface
@@ -199,27 +87,50 @@ public:
size_t get_max_recv_samps_per_packet(void) const;
bool recv_async_msg(uhd::async_metadata_t &, double);
- void update_xport_channel_mapping(void);
-
- //public frame sizes, set by mboard, used by io impl
- size_t recv_frame_size, send_frame_size;
-
- std::vector<uhd::transport::zero_copy_if::sptr> dsp_xports;
- std::vector<uhd::transport::zero_copy_if::sptr> err_xports;
-
private:
- //device properties interface
- void get(const wax::obj &, wax::obj &);
- void set(const wax::obj &, const wax::obj &);
+ uhd::property_tree::sptr _tree;
+ struct mb_container_type{
+ usrp2_iface::sptr iface;
+ usrp2_clock_ctrl::sptr clock;
+ usrp2_codec_ctrl::sptr codec;
+ gps_ctrl::sptr gps;
+ rx_frontend_core_200::sptr rx_fe;
+ tx_frontend_core_200::sptr tx_fe;
+ std::vector<rx_dsp_core_200::sptr> rx_dsps;
+ tx_dsp_core_200::sptr tx_dsp;
+ time64_core_200::sptr time64;
+ std::vector<uhd::transport::zero_copy_if::sptr> rx_dsp_xports;
+ uhd::transport::zero_copy_if::sptr tx_dsp_xport;
+ uhd::usrp::dboard_manager::sptr dboard_manager;
+ uhd::usrp::dboard_iface::sptr dboard_iface;
+ size_t rx_chan_occ, tx_chan_occ;
+ };
+ uhd::dict<std::string, mb_container_type> _mbc;
+
+ void set_mb_eeprom(const std::string &, const uhd::usrp::mboard_eeprom_t &);
+ void set_db_eeprom(const std::string &, const std::string &, const uhd::usrp::dboard_eeprom_t &);
+
+ uhd::sensor_value_t get_mimo_locked(const std::string &);
+ uhd::sensor_value_t get_ref_locked(const std::string &);
- //pointers to mboards on this device (think mimo setup)
- std::vector<usrp2_mboard_impl::sptr> _mboards;
- uhd::dict<std::string, usrp2_mboard_impl::sptr> _mboard_dict;
+ //device properties interface
+ void get(const wax::obj &, wax::obj &val){
+ val = _tree; //entry point into property tree
+ }
//io impl methods and members
uhd::otw_type_t _rx_otw_type, _tx_otw_type;
UHD_PIMPL_DECL(io_impl) _io_impl;
void io_init(void);
+ void update_tick_rate(const double rate);
+ void update_rx_samp_rate(const double rate);
+ void update_tx_samp_rate(const double rate);
+ //update spec methods are coercers until we only accept db_name == A
+ uhd::usrp::subdev_spec_t update_rx_subdev_spec(const std::string &, const uhd::usrp::subdev_spec_t &);
+ uhd::usrp::subdev_spec_t update_tx_subdev_spec(const std::string &, const uhd::usrp::subdev_spec_t &);
+ double set_tx_dsp_freq(const std::string &, const double);
+ uhd::meta_range_t get_tx_dsp_freq_range(const std::string &);
+ void update_clock_source(const std::string &, const std::string &);
};
#endif /* INCLUDED_USRP2_IMPL_HPP */
diff --git a/host/lib/usrp/usrp2/usrp2_regs.hpp b/host/lib/usrp/usrp2/usrp2_regs.hpp
index dbb78275b..555e4a3e7 100644
--- a/host/lib/usrp/usrp2/usrp2_regs.hpp
+++ b/host/lib/usrp/usrp2/usrp2_regs.hpp
@@ -54,6 +54,8 @@
#define U2_REG_SR_ADDR(sr) (SETTING_REGS_BASE + (4 * (sr)))
+#define U2_REG_ROUTER_CTRL_PORTS U2_REG_SR_ADDR(SR_BUF_POOL) + 8
+
/////////////////////////////////////////////////
// SPI Slave Constants
////////////////////////////////////////////////
@@ -90,25 +92,6 @@
#define U2_FLAG_MISC_CTRL_ADC_OFF 0x00
/////////////////////////////////////////////////
-// VITA49 64 bit time (write only)
-////////////////////////////////////////////////
-#define U2_REG_TIME64_SECS U2_REG_SR_ADDR(SR_TIME64 + 0)
-#define U2_REG_TIME64_TICKS U2_REG_SR_ADDR(SR_TIME64 + 1)
-#define U2_REG_TIME64_FLAGS U2_REG_SR_ADDR(SR_TIME64 + 2)
-#define U2_REG_TIME64_IMM U2_REG_SR_ADDR(SR_TIME64 + 3)
-#define U2_REG_TIME64_TPS U2_REG_SR_ADDR(SR_TIME64 + 4)
-#define U2_REG_TIME64_MIMO_SYNC U2_REG_SR_ADDR(SR_TIME64 + 5)
-
-//pps flags (see above)
-#define U2_FLAG_TIME64_PPS_NEGEDGE (0 << 0)
-#define U2_FLAG_TIME64_PPS_POSEDGE (1 << 0)
-#define U2_FLAG_TIME64_PPS_SMA (0 << 1)
-#define U2_FLAG_TIME64_PPS_MIMO (1 << 1)
-
-#define U2_FLAG_TIME64_LATCH_NOW 1
-#define U2_FLAG_TIME64_LATCH_NEXT_PPS 0
-
-/////////////////////////////////////////////////
// Readback regs
////////////////////////////////////////////////
#define U2_REG_STATUS READBACK_BASE + 4*8
@@ -119,26 +102,6 @@
#define U2_REG_TIME64_SECS_RB_PPS READBACK_BASE + 4*14
#define U2_REG_TIME64_TICKS_RB_PPS READBACK_BASE + 4*15
-/////////////////////////////////////////////////
-// DSP TX Regs
-////////////////////////////////////////////////
-#define U2_REG_DSP_TX_FREQ U2_REG_SR_ADDR(SR_TX_DSP + 0)
-#define U2_REG_DSP_TX_SCALE_IQ U2_REG_SR_ADDR(SR_TX_DSP + 1)
-#define U2_REG_DSP_TX_INTERP_RATE U2_REG_SR_ADDR(SR_TX_DSP + 2)
-#define U2_REG_DSP_TX_MUX U2_REG_SR_ADDR(SR_TX_DSP + 4)
-
-/////////////////////////////////////////////////
-// DSP RX Regs
-////////////////////////////////////////////////
-#define U2_REG_DSP_RX_HELPER(which, offset) ((which == 0)? \
- (U2_REG_SR_ADDR(SR_RX_DSP0 + offset)) : \
- (U2_REG_SR_ADDR(SR_RX_DSP1 + offset)))
-
-#define U2_REG_DSP_RX_FREQ(which) U2_REG_DSP_RX_HELPER(which, 0)
-#define U2_REG_DSP_RX_SCALE_IQ(which) U2_REG_DSP_RX_HELPER(which, 1)
-#define U2_REG_DSP_RX_DECIM(which) U2_REG_DSP_RX_HELPER(which, 2)
-#define U2_REG_DSP_RX_MUX(which) U2_REG_DSP_RX_HELPER(which, 5)
-
////////////////////////////////////////////////
// GPIO
////////////////////////////////////////////////
@@ -165,38 +128,4 @@
#define U2_REG_ATR_FULL_TXSIDE ATR_BASE + 12
#define U2_REG_ATR_FULL_RXSIDE ATR_BASE + 14
-///////////////////////////////////////////////////
-// RX CTRL regs
-///////////////////////////////////////////////////
-#define U2_REG_RX_CTRL_HELPER(which, offset) ((which == 0)? \
- (U2_REG_SR_ADDR(SR_RX_CTRL0 + offset)) : \
- (U2_REG_SR_ADDR(SR_RX_CTRL1 + offset)))
-
-#define U2_REG_RX_CTRL_STREAM_CMD(which) U2_REG_RX_CTRL_HELPER(which, 0)
-#define U2_REG_RX_CTRL_TIME_SECS(which) U2_REG_RX_CTRL_HELPER(which, 1)
-#define U2_REG_RX_CTRL_TIME_TICKS(which) U2_REG_RX_CTRL_HELPER(which, 2)
-#define U2_REG_RX_CTRL_CLEAR(which) U2_REG_RX_CTRL_HELPER(which, 3)
-#define U2_REG_RX_CTRL_VRT_HDR(which) U2_REG_RX_CTRL_HELPER(which, 4)
-#define U2_REG_RX_CTRL_VRT_SID(which) U2_REG_RX_CTRL_HELPER(which, 5)
-#define U2_REG_RX_CTRL_VRT_TLR(which) U2_REG_RX_CTRL_HELPER(which, 6)
-#define U2_REG_RX_CTRL_NSAMPS_PP(which) U2_REG_RX_CTRL_HELPER(which, 7)
-#define U2_REG_RX_CTRL_NCHANNELS(which) U2_REG_RX_CTRL_HELPER(which, 8)
-
-///////////////////////////////////////////////////
-// TX CTRL regs
-///////////////////////////////////////////////////
-#define U2_REG_TX_CTRL_NUM_CHAN U2_REG_SR_ADDR(SR_TX_CTRL + 0)
-#define U2_REG_TX_CTRL_CLEAR_STATE U2_REG_SR_ADDR(SR_TX_CTRL + 1)
-#define U2_REG_TX_CTRL_REPORT_SID U2_REG_SR_ADDR(SR_TX_CTRL + 2)
-#define U2_REG_TX_CTRL_POLICY U2_REG_SR_ADDR(SR_TX_CTRL + 3)
-#define U2_REG_TX_CTRL_CYCLES_PER_UP U2_REG_SR_ADDR(SR_TX_CTRL + 4)
-#define U2_REG_TX_CTRL_PACKETS_PER_UP U2_REG_SR_ADDR(SR_TX_CTRL + 5)
-
-#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)
-
-//enable flag for registers: cycles and packets per update packet
-#define U2_FLAG_TX_CTRL_UP_ENB (1ul << 31)
-
#endif /* INCLUDED_USRP2_REGS_HPP */
diff --git a/host/lib/usrp/usrp_e100/codec_impl.cpp b/host/lib/usrp/usrp_e100/codec_impl.cpp
deleted file mode 100644
index ae198aaa5..000000000
--- a/host/lib/usrp/usrp_e100/codec_impl.cpp
+++ /dev/null
@@ -1,149 +0,0 @@
-//
-// Copyright 2010-2011 Ettus Research LLC
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// 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 "usrp_e100_impl.hpp"
-#include <uhd/exception.hpp>
-#include <uhd/usrp/codec_props.hpp>
-#include <boost/bind.hpp>
-
-using namespace uhd;
-using namespace uhd::usrp;
-
-/***********************************************************************
- * Helper Methods
- **********************************************************************/
-void usrp_e100_impl::codec_init(void){
- //make proxies
- _rx_codec_proxy = wax_obj_proxy::make(
- boost::bind(&usrp_e100_impl::rx_codec_get, this, _1, _2),
- boost::bind(&usrp_e100_impl::rx_codec_set, this, _1, _2)
- );
- _tx_codec_proxy = wax_obj_proxy::make(
- boost::bind(&usrp_e100_impl::tx_codec_get, this, _1, _2),
- boost::bind(&usrp_e100_impl::tx_codec_set, this, _1, _2)
- );
-}
-
-/***********************************************************************
- * RX Codec Properties
- **********************************************************************/
-static const std::string ad9862_pga_gain_name = "ad9862 pga";
-
-void usrp_e100_impl::rx_codec_get(const wax::obj &key_, wax::obj &val){
- named_prop_t key = named_prop_t::extract(key_);
-
- //handle the get request conditioned on the key
- switch(key.as<codec_prop_t>()){
- case CODEC_PROP_NAME:
- val = std::string("usrp-e adc - ad9522");
- return;
-
- case CODEC_PROP_OTHERS:
- val = prop_names_t();
- return;
-
- case CODEC_PROP_GAIN_NAMES:
- val = prop_names_t(1, ad9862_pga_gain_name);
- return;
-
- case CODEC_PROP_GAIN_RANGE:
- UHD_ASSERT_THROW(key.name == ad9862_pga_gain_name);
- val = usrp_e100_codec_ctrl::rx_pga_gain_range;
- return;
-
- case CODEC_PROP_GAIN_I:
- UHD_ASSERT_THROW(key.name == ad9862_pga_gain_name);
- val = _codec_ctrl->get_rx_pga_gain('A');
- return;
-
- case CODEC_PROP_GAIN_Q:
- UHD_ASSERT_THROW(key.name == ad9862_pga_gain_name);
- val = _codec_ctrl->get_rx_pga_gain('B');
- return;
-
- default: UHD_THROW_PROP_GET_ERROR();
- }
-}
-
-void usrp_e100_impl::rx_codec_set(const wax::obj &key_, const wax::obj &val){
- named_prop_t key = named_prop_t::extract(key_);
-
- //handle the set request conditioned on the key
- switch(key.as<codec_prop_t>()){
- case CODEC_PROP_GAIN_I:
- UHD_ASSERT_THROW(key.name == ad9862_pga_gain_name);
- _codec_ctrl->set_rx_pga_gain(val.as<double>(), 'A');
- return;
-
- case CODEC_PROP_GAIN_Q:
- UHD_ASSERT_THROW(key.name == ad9862_pga_gain_name);
- _codec_ctrl->set_rx_pga_gain(val.as<double>(), 'B');
- return;
-
- default: UHD_THROW_PROP_SET_ERROR();
- }
-}
-
-/***********************************************************************
- * TX Codec Properties
- **********************************************************************/
-void usrp_e100_impl::tx_codec_get(const wax::obj &key_, wax::obj &val){
- named_prop_t key = named_prop_t::extract(key_);
-
- //handle the get request conditioned on the key
- switch(key.as<codec_prop_t>()){
- case CODEC_PROP_NAME:
- val = std::string("usrp-e dac - ad9522");
- return;
-
- case CODEC_PROP_OTHERS:
- val = prop_names_t();
- return;
-
- case CODEC_PROP_GAIN_NAMES:
- val = prop_names_t(1, ad9862_pga_gain_name);
- return;
-
- case CODEC_PROP_GAIN_RANGE:
- UHD_ASSERT_THROW(key.name == ad9862_pga_gain_name);
- val = usrp_e100_codec_ctrl::tx_pga_gain_range;
- return;
-
- case CODEC_PROP_GAIN_I: //only one gain for I and Q
- case CODEC_PROP_GAIN_Q:
- UHD_ASSERT_THROW(key.name == ad9862_pga_gain_name);
- val = _codec_ctrl->get_tx_pga_gain();
- return;
-
- default: UHD_THROW_PROP_GET_ERROR();
- }
-}
-
-void usrp_e100_impl::tx_codec_set(const wax::obj &key_, const wax::obj &val){
- named_prop_t key = named_prop_t::extract(key_);
-
- //handle the set request conditioned on the key
- switch(key.as<codec_prop_t>()){
- case CODEC_PROP_GAIN_I: //only one gain for I and Q
- case CODEC_PROP_GAIN_Q:
- UHD_ASSERT_THROW(key.name == ad9862_pga_gain_name);
- _codec_ctrl->set_tx_pga_gain(val.as<double>());
- return;
-
- default: UHD_THROW_PROP_SET_ERROR();
- }
-}
diff --git a/host/lib/usrp/usrp_e100/dboard_impl.cpp b/host/lib/usrp/usrp_e100/dboard_impl.cpp
deleted file mode 100644
index f6bbbd5e8..000000000
--- a/host/lib/usrp/usrp_e100/dboard_impl.cpp
+++ /dev/null
@@ -1,185 +0,0 @@
-//
-// Copyright 2010-2011 Ettus Research LLC
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// 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 "usrp_e100_impl.hpp"
-#include "usrp_e100_regs.hpp"
-#include <uhd/exception.hpp>
-#include <uhd/usrp/dboard_props.hpp>
-#include <uhd/usrp/subdev_props.hpp>
-#include <uhd/usrp/misc_utils.hpp>
-#include <boost/bind.hpp>
-#include <iostream>
-
-using namespace uhd;
-using namespace uhd::usrp;
-
-/***********************************************************************
- * Dboard Initialization
- **********************************************************************/
-void usrp_e100_impl::dboard_init(void){
- //read the dboard eeprom to extract the dboard ids
- _rx_db_eeprom.load(*_iface, I2C_ADDR_RX_DB);
- _tx_db_eeprom.load(*_iface, I2C_ADDR_TX_DB);
- _gdb_eeprom.load(*_iface, I2C_ADDR_TX_DB ^ 5);
-
- //create a new dboard interface and manager
- _dboard_iface = make_usrp_e100_dboard_iface(
- _iface, _clock_ctrl, _codec_ctrl
- );
- _dboard_manager = dboard_manager::make(
- _rx_db_eeprom.id,
- ((_gdb_eeprom.id == dboard_id_t::none())? _tx_db_eeprom : _gdb_eeprom).id,
- _dboard_iface
- );
-
- //setup the dboard proxies
- _rx_dboard_proxy = wax_obj_proxy::make(
- boost::bind(&usrp_e100_impl::rx_dboard_get, this, _1, _2),
- boost::bind(&usrp_e100_impl::rx_dboard_set, this, _1, _2)
- );
- _tx_dboard_proxy = wax_obj_proxy::make(
- boost::bind(&usrp_e100_impl::tx_dboard_get, this, _1, _2),
- boost::bind(&usrp_e100_impl::tx_dboard_set, this, _1, _2)
- );
-}
-
-/***********************************************************************
- * RX Dboard Get
- **********************************************************************/
-void usrp_e100_impl::rx_dboard_get(const wax::obj &key_, wax::obj &val){
- named_prop_t key = named_prop_t::extract(key_);
-
- //handle the get request conditioned on the key
- switch(key.as<dboard_prop_t>()){
- case DBOARD_PROP_NAME:
- val = std::string("usrp-e dboard (rx unit)");
- return;
-
- case DBOARD_PROP_SUBDEV:
- val = _dboard_manager->get_rx_subdev(key.name);
- return;
-
- case DBOARD_PROP_SUBDEV_NAMES:
- val = _dboard_manager->get_rx_subdev_names();
- return;
-
- case DBOARD_PROP_DBOARD_EEPROM:
- val = _rx_db_eeprom;
- return;
-
- case DBOARD_PROP_DBOARD_IFACE:
- val = _dboard_iface;
- return;
-
- case DBOARD_PROP_CODEC:
- val = _rx_codec_proxy->get_link();
- return;
-
- case DBOARD_PROP_GAIN_GROUP:
- val = make_gain_group(
- _rx_db_eeprom.id,
- _dboard_manager->get_rx_subdev(key.name),
- _rx_codec_proxy->get_link(),
- GAIN_GROUP_POLICY_RX
- );
- return;
-
- default: UHD_THROW_PROP_GET_ERROR();
- }
-}
-
-/***********************************************************************
- * RX Dboard Set
- **********************************************************************/
-void usrp_e100_impl::rx_dboard_set(const wax::obj &key, const wax::obj &val){
- switch(key.as<dboard_prop_t>()){
- case DBOARD_PROP_DBOARD_EEPROM:
- _rx_db_eeprom = val.as<dboard_eeprom_t>();
- _rx_db_eeprom.store(*_iface, I2C_ADDR_RX_DB);
- return;
-
- default: UHD_THROW_PROP_SET_ERROR();
- }
-}
-
-/***********************************************************************
- * TX Dboard Get
- **********************************************************************/
-void usrp_e100_impl::tx_dboard_get(const wax::obj &key_, wax::obj &val){
- named_prop_t key = named_prop_t::extract(key_);
-
- //handle the get request conditioned on the key
- switch(key.as<dboard_prop_t>()){
- case DBOARD_PROP_NAME:
- val = std::string("usrp-e dboard (tx unit)");
- return;
-
- case DBOARD_PROP_SUBDEV:
- val = _dboard_manager->get_tx_subdev(key.name);
- return;
-
- case DBOARD_PROP_SUBDEV_NAMES:
- val = _dboard_manager->get_tx_subdev_names();
- return;
-
- case DBOARD_PROP_DBOARD_EEPROM:
- val = _tx_db_eeprom;
- return;
-
- case DBOARD_PROP_GBOARD_EEPROM:
- val = _gdb_eeprom;
- return;
-
- case DBOARD_PROP_DBOARD_IFACE:
- val = _dboard_iface;
- return;
-
- case DBOARD_PROP_CODEC:
- val = _tx_codec_proxy->get_link();
- return;
-
- case DBOARD_PROP_GAIN_GROUP:
- val = make_gain_group(
- _tx_db_eeprom.id,
- _dboard_manager->get_tx_subdev(key.name),
- _tx_codec_proxy->get_link(),
- GAIN_GROUP_POLICY_TX
- );
- return;
-
- default: UHD_THROW_PROP_GET_ERROR();
- }
-}
-
-/***********************************************************************
- * TX Dboard Set
- **********************************************************************/
-void usrp_e100_impl::tx_dboard_set(const wax::obj &key, const wax::obj &val){
- switch(key.as<dboard_prop_t>()){
- case DBOARD_PROP_DBOARD_EEPROM:
- _tx_db_eeprom = val.as<dboard_eeprom_t>();
- _tx_db_eeprom.store(*_iface, I2C_ADDR_TX_DB);
- return;
-
- case DBOARD_PROP_GBOARD_EEPROM:
- _gdb_eeprom = val.as<dboard_eeprom_t>();
- _gdb_eeprom.store(*_iface, I2C_ADDR_TX_DB ^ 5);
- return;
-
- default: UHD_THROW_PROP_SET_ERROR();
- }
-}
diff --git a/host/lib/usrp/usrp_e100/dsp_impl.cpp b/host/lib/usrp/usrp_e100/dsp_impl.cpp
deleted file mode 100644
index 93034b5dc..000000000
--- a/host/lib/usrp/usrp_e100/dsp_impl.cpp
+++ /dev/null
@@ -1,190 +0,0 @@
-//
-// Copyright 2010-2011 Ettus Research LLC
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// 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 "usrp_e100_impl.hpp"
-#include "usrp_e100_regs.hpp"
-#include <uhd/usrp/dsp_utils.hpp>
-#include <uhd/usrp/dsp_props.hpp>
-#include <boost/math/special_functions/round.hpp>
-#include <boost/bind.hpp>
-
-#define rint boost::math::iround
-
-using namespace uhd;
-using namespace uhd::usrp;
-
-/***********************************************************************
- * RX DDC Initialization
- **********************************************************************/
-void usrp_e100_impl::rx_ddc_init(void){
- _rx_ddc_proxy = wax_obj_proxy::make(
- boost::bind(&usrp_e100_impl::rx_ddc_get, this, _1, _2),
- boost::bind(&usrp_e100_impl::rx_ddc_set, this, _1, _2)
- );
-
- //initial config and update
- rx_ddc_set(DSP_PROP_FREQ_SHIFT, double(0));
- rx_ddc_set(DSP_PROP_HOST_RATE, double(16e6));
-}
-
-/***********************************************************************
- * RX DDC Get
- **********************************************************************/
-void usrp_e100_impl::rx_ddc_get(const wax::obj &key_, wax::obj &val){
- named_prop_t key = named_prop_t::extract(key_);
-
- switch(key.as<dsp_prop_t>()){
- case DSP_PROP_NAME:
- val = std::string("usrp-e ddc0");
- return;
-
- case DSP_PROP_OTHERS:
- val = prop_names_t(); //empty
- return;
-
- case DSP_PROP_FREQ_SHIFT:
- val = _ddc_freq;
- return;
-
- case DSP_PROP_CODEC_RATE:
- val = _clock_ctrl->get_fpga_clock_rate();
- return;
-
- case DSP_PROP_HOST_RATE:
- val = _clock_ctrl->get_fpga_clock_rate()/_ddc_decim;
- return;
-
- default: UHD_THROW_PROP_GET_ERROR();
- }
-}
-
-/***********************************************************************
- * RX DDC Set
- **********************************************************************/
-void usrp_e100_impl::rx_ddc_set(const wax::obj &key_, const wax::obj &val){
- named_prop_t key = named_prop_t::extract(key_);
-
- switch(key.as<dsp_prop_t>()){
-
- case DSP_PROP_STREAM_CMD:
- issue_stream_cmd(val.as<stream_cmd_t>());
- return;
-
- case DSP_PROP_FREQ_SHIFT:{
- double new_freq = val.as<double>();
- _iface->poke32(UE_REG_DSP_RX_FREQ,
- dsp_type1::calc_cordic_word_and_update(new_freq, _clock_ctrl->get_fpga_clock_rate())
- );
- _ddc_freq = new_freq; //shadow
- }
- return;
-
- case DSP_PROP_HOST_RATE:{
- //set the decimation
- _ddc_decim = rint(_clock_ctrl->get_fpga_clock_rate()/val.as<double>());
- _iface->poke32(UE_REG_DSP_RX_DECIM_RATE, dsp_type1::calc_cic_filter_word(_ddc_decim));
-
- //set the scaling
- static const boost::int16_t default_rx_scale_iq = 1024;
- _iface->poke32(UE_REG_DSP_RX_SCALE_IQ,
- dsp_type1::calc_iq_scale_word(default_rx_scale_iq, default_rx_scale_iq)
- );
- }
- this->update_xport_channel_mapping(); //rate changed -> update
- return;
-
- default: UHD_THROW_PROP_SET_ERROR();
- }
-}
-
-/***********************************************************************
- * TX DUC Initialization
- **********************************************************************/
-void usrp_e100_impl::tx_duc_init(void){
- _tx_duc_proxy = wax_obj_proxy::make(
- boost::bind(&usrp_e100_impl::tx_duc_get, this, _1, _2),
- boost::bind(&usrp_e100_impl::tx_duc_set, this, _1, _2)
- );
-
- //initial config and update
- tx_duc_set(DSP_PROP_FREQ_SHIFT, double(0));
- tx_duc_set(DSP_PROP_HOST_RATE, double(16e6));
-}
-
-/***********************************************************************
- * TX DUC Get
- **********************************************************************/
-void usrp_e100_impl::tx_duc_get(const wax::obj &key_, wax::obj &val){
- named_prop_t key = named_prop_t::extract(key_);
-
- switch(key.as<dsp_prop_t>()){
- case DSP_PROP_NAME:
- val = std::string("usrp-e duc0");
- return;
-
- case DSP_PROP_OTHERS:
- val = prop_names_t(); //empty
- return;
-
- case DSP_PROP_FREQ_SHIFT:
- val = _duc_freq;
- return;
-
- case DSP_PROP_CODEC_RATE:
- val = _clock_ctrl->get_fpga_clock_rate();
- return;
-
- case DSP_PROP_HOST_RATE:
- val = _clock_ctrl->get_fpga_clock_rate()/_duc_interp;
- return;
-
- default: UHD_THROW_PROP_GET_ERROR();
- }
-}
-
-/***********************************************************************
- * TX DUC Set
- **********************************************************************/
-void usrp_e100_impl::tx_duc_set(const wax::obj &key_, const wax::obj &val){
- named_prop_t key = named_prop_t::extract(key_);
-
- switch(key.as<dsp_prop_t>()){
-
- case DSP_PROP_FREQ_SHIFT:{
- double new_freq = val.as<double>();
- _iface->poke32(UE_REG_DSP_TX_FREQ,
- dsp_type1::calc_cordic_word_and_update(new_freq, _clock_ctrl->get_fpga_clock_rate())
- );
- _duc_freq = new_freq; //shadow
- }
- return;
-
- case DSP_PROP_HOST_RATE:{
- _duc_interp = rint(_clock_ctrl->get_fpga_clock_rate()/val.as<double>());
-
- //set the interpolation
- _iface->poke32(UE_REG_DSP_TX_INTERP_RATE, dsp_type1::calc_cic_filter_word(_duc_interp));
-
- //set the scaling
- _iface->poke32(UE_REG_DSP_TX_SCALE_IQ, dsp_type1::calc_iq_scale_word(_duc_interp));
- }
- this->update_xport_channel_mapping(); //rate changed -> update
- return;
-
- default: UHD_THROW_PROP_SET_ERROR();
- }
-}
diff --git a/host/lib/usrp/usrp_e100/io_impl.cpp b/host/lib/usrp/usrp_e100/io_impl.cpp
deleted file mode 100644
index 998a715fe..000000000
--- a/host/lib/usrp/usrp_e100/io_impl.cpp
+++ /dev/null
@@ -1,315 +0,0 @@
-//
-// Copyright 2010-2011 Ettus Research LLC
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// 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 "../../transport/super_recv_packet_handler.hpp"
-#include "../../transport/super_send_packet_handler.hpp"
-#include "usrp_e100_impl.hpp"
-#include "usrp_e100_regs.hpp"
-#include <uhd/utils/msg.hpp>
-#include <uhd/utils/log.hpp>
-#include <uhd/usrp/dsp_utils.hpp>
-#include <uhd/usrp/dsp_props.hpp>
-#include <uhd/utils/thread_priority.hpp>
-#include <uhd/transport/bounded_buffer.hpp>
-#include <boost/bind.hpp>
-#include <boost/format.hpp>
-#include <boost/thread/thread.hpp>
-#include <boost/thread/barrier.hpp>
-#include <sstream>
-
-using namespace uhd;
-using namespace uhd::usrp;
-using namespace uhd::transport;
-
-/***********************************************************************
- * Constants
- **********************************************************************/
-static const size_t rx_data_inline_sid = 1;
-static const size_t tx_async_report_sid = 2;
-static const int underflow_flags = async_metadata_t::EVENT_CODE_UNDERFLOW | async_metadata_t::EVENT_CODE_UNDERFLOW_IN_PACKET;
-#define fp_recv_debug false
-
-/***********************************************************************
- * io impl details (internal to this file)
- * - pirate crew of 1
- * - bounded buffer
- * - thread loop
- * - vrt packet handler states
- **********************************************************************/
-struct usrp_e100_impl::io_impl{
- io_impl(zero_copy_if::sptr &xport):
- data_xport(xport),
- recv_pirate_booty(data_xport->get_num_recv_frames()),
- async_msg_fifo(100/*messages deep*/)
- {
- /* NOP */
- }
-
- ~io_impl(void){
- recv_pirate_crew_raiding = false;
- recv_pirate_crew.interrupt_all();
- recv_pirate_crew.join_all();
- }
-
- managed_recv_buffer::sptr get_recv_buff(double timeout){
- boost::this_thread::disable_interruption di; //disable because the wait can throw
- managed_recv_buffer::sptr buff;
- recv_pirate_booty.pop_with_timed_wait(buff, timeout);
- return buff; //ASSUME buff == NULL when pop times-out
- }
-
- //The data transport is listed first so that it is deconstructed last,
- //which is after the states and booty which may hold managed buffers.
- //This comment is invalid because its now a reference and not stored here.
- zero_copy_if::sptr &data_xport;
-
- //state management for the vrt packet handler code
- sph::recv_packet_handler recv_handler;
- sph::send_packet_handler send_handler;
- bool continuous_streaming;
-
- //a pirate's life is the life for me!
- void recv_pirate_loop(boost::barrier &, usrp_e100_clock_ctrl::sptr);
- bounded_buffer<managed_recv_buffer::sptr> recv_pirate_booty;
- bounded_buffer<async_metadata_t> async_msg_fifo;
- boost::thread_group recv_pirate_crew;
- bool recv_pirate_crew_raiding;
-};
-
-/***********************************************************************
- * Receive Pirate Loop
- * - while raiding, loot for recv buffers
- * - put booty into the alignment buffer
- **********************************************************************/
-void usrp_e100_impl::io_impl::recv_pirate_loop(
- boost::barrier &spawn_barrier, usrp_e100_clock_ctrl::sptr clock_ctrl
-){
- recv_pirate_crew_raiding = true;
- spawn_barrier.wait();
- set_thread_priority_safe();
-
- while(recv_pirate_crew_raiding){
- managed_recv_buffer::sptr buff = this->data_xport->get_recv_buff();
- if (not buff.get()) continue; //ignore timeout/error buffers
-
- if (fp_recv_debug){
- std::ostringstream ss;
- ss << "len " << buff->size() << std::endl;
- for (size_t i = 0; i < 9; i++){
- ss << boost::format(" 0x%08x") % buff->cast<const boost::uint32_t *>()[i] << std::endl;
- }
- ss << std::endl << std::endl;
- UHD_LOGV(always) << ss.str();
- }
-
- try{
- //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);
- const boost::uint32_t *vrt_hdr = buff->cast<const boost::uint32_t *>();
-
- //handle an rx data packet or inline message
- if (uhd::wtohx(vrt_hdr[1]) == rx_data_inline_sid){ //ASSUME has_sid
- if (fp_recv_debug) UHD_LOGV(always) << "this is rx_data_inline_sid\n";
- //same number of frames as the data transport -> always immediate
- recv_pirate_booty.push_with_wait(buff);
- continue;
- }
-
- //unpack the vrt header and process below...
- vrt::if_hdr_unpack_le(vrt_hdr, if_packet_info);
-
- //handle a tx async report message
- if (if_packet_info.sid == tx_async_report_sid and if_packet_info.packet_type != vrt::if_packet_info_t::PACKET_TYPE_DATA){
- if (fp_recv_debug) UHD_LOGV(always) << "this is tx_async_report_sid\n";
-
- //fill in the async metadata
- async_metadata_t metadata;
- metadata.channel = 0;
- 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), clock_ctrl->get_fpga_clock_rate()
- );
- metadata.event_code = async_metadata_t::event_code_t(sph::get_context_code(vrt_hdr, if_packet_info));
-
- //print the famous U, and push the metadata into the message queue
- if (metadata.event_code & underflow_flags) UHD_MSG(fastpath) << "U";
- async_msg_fifo.push_with_pop_on_full(metadata);
- continue;
- }
-
- //TODO replace this below with a UHD_MSG(error)
- if (fp_recv_debug) UHD_LOGV(always) << "this is unknown packet\n";
-
- }catch(const std::exception &e){
- UHD_MSG(error) << "Error (usrp-e recv pirate loop): " << e.what() << std::endl;
- }
- }
-}
-
-/***********************************************************************
- * Helper Functions
- **********************************************************************/
-void usrp_e100_impl::io_init(void){
- //setup otw types
- _send_otw_type.width = 16;
- _send_otw_type.shift = 0;
- _send_otw_type.byteorder = otw_type_t::BO_LITTLE_ENDIAN;
-
- _recv_otw_type.width = 16;
- _recv_otw_type.shift = 0;
- _recv_otw_type.byteorder = otw_type_t::BO_LITTLE_ENDIAN;
-
- //setup before the registers (transport called to calculate max spp)
- _io_impl = UHD_PIMPL_MAKE(io_impl, (_data_xport));
-
- //clear state machines
- _iface->poke32(UE_REG_CTRL_RX_CLEAR, 0);
- _iface->poke32(UE_REG_CTRL_TX_CLEAR, 0);
-
- //setup rx data path
- _iface->poke32(UE_REG_CTRL_RX_NSAMPS_PER_PKT, get_max_recv_samps_per_packet());
- _iface->poke32(UE_REG_CTRL_RX_NCHANNELS, 1);
- _iface->poke32(UE_REG_CTRL_RX_VRT_HEADER, 0
- | (0x1 << 28) //if data with stream id
- | (0x1 << 26) //has trailer
- | (0x3 << 22) //integer time other
- | (0x1 << 20) //fractional time sample count
- );
- _iface->poke32(UE_REG_CTRL_RX_VRT_STREAM_ID, rx_data_inline_sid);
- _iface->poke32(UE_REG_CTRL_RX_VRT_TRAILER, 0);
-
- //setup the tx policy
- _iface->poke32(UE_REG_CTRL_TX_REPORT_SID, tx_async_report_sid);
- _iface->poke32(UE_REG_CTRL_TX_POLICY, UE_FLAG_CTRL_TX_POLICY_NEXT_PACKET);
-
- //spawn a pirate, yarrr!
- boost::barrier spawn_barrier(2);
- _io_impl->recv_pirate_crew.create_thread(boost::bind(
- &usrp_e100_impl::io_impl::recv_pirate_loop, _io_impl.get(),
- boost::ref(spawn_barrier), _clock_ctrl
- ));
- spawn_barrier.wait();
- //update mapping here since it didnt b4 when io init not called first
- update_xport_channel_mapping();
-}
-
-void usrp_e100_impl::update_xport_channel_mapping(void){
- if (_io_impl.get() == NULL) return; //not inited yet
-
- //set all of the relevant properties on the handler
- boost::mutex::scoped_lock recv_lock = _io_impl->recv_handler.get_scoped_lock();
- _io_impl->recv_handler.resize(_rx_subdev_spec.size());
- _io_impl->recv_handler.set_vrt_unpacker(&vrt::if_hdr_unpack_le);
- _io_impl->recv_handler.set_tick_rate(_clock_ctrl->get_fpga_clock_rate());
- _io_impl->recv_handler.set_samp_rate(_rx_ddc_proxy->get_link()[DSP_PROP_HOST_RATE].as<double>());
- for (size_t chan = 0; chan < _io_impl->recv_handler.size(); chan++){
- _io_impl->recv_handler.set_xport_chan_get_buff(chan, boost::bind(
- &usrp_e100_impl::io_impl::get_recv_buff, _io_impl.get(), _1
- ));
- _io_impl->recv_handler.set_overflow_handler(chan, boost::bind(
- &usrp_e100_impl::handle_overrun, this, chan
- ));
- }
- _io_impl->recv_handler.set_converter(_recv_otw_type);
-
- //set all of the relevant properties on the handler
- boost::mutex::scoped_lock send_lock = _io_impl->send_handler.get_scoped_lock();
- _io_impl->send_handler.resize(_tx_subdev_spec.size());
- _io_impl->send_handler.set_vrt_packer(&vrt::if_hdr_pack_le);
- _io_impl->send_handler.set_tick_rate(_clock_ctrl->get_fpga_clock_rate());
- _io_impl->send_handler.set_samp_rate(_tx_duc_proxy->get_link()[DSP_PROP_HOST_RATE].as<double>());
- for (size_t chan = 0; chan < _io_impl->send_handler.size(); chan++){
- _io_impl->send_handler.set_xport_chan_get_buff(chan, boost::bind(
- &uhd::transport::zero_copy_if::get_send_buff, _io_impl->data_xport, _1
- ));
- }
- _io_impl->send_handler.set_converter(_send_otw_type);
- _io_impl->send_handler.set_max_samples_per_packet(get_max_send_samps_per_packet());
-}
-
-void usrp_e100_impl::issue_stream_cmd(const stream_cmd_t &stream_cmd){
- _io_impl->continuous_streaming = (stream_cmd.stream_mode == stream_cmd_t::STREAM_MODE_START_CONTINUOUS);
- _iface->poke32(UE_REG_CTRL_RX_STREAM_CMD, dsp_type1::calc_stream_cmd_word(stream_cmd));
- _iface->poke32(UE_REG_CTRL_RX_TIME_SECS, boost::uint32_t(stream_cmd.time_spec.get_full_secs()));
- _iface->poke32(UE_REG_CTRL_RX_TIME_TICKS, stream_cmd.time_spec.get_tick_count(_clock_ctrl->get_fpga_clock_rate()));
-}
-
-void usrp_e100_impl::handle_overrun(size_t /*chan*/){
- if (_io_impl->continuous_streaming){
- this->issue_stream_cmd(stream_cmd_t::STREAM_MODE_START_CONTINUOUS);
- }
-}
-
-/***********************************************************************
- * Data Send
- **********************************************************************/
-size_t usrp_e100_impl::get_max_send_samps_per_packet(void) const{
- static const size_t hdr_size = 0
- + vrt::max_if_hdr_words32*sizeof(boost::uint32_t)
- - sizeof(vrt::if_packet_info_t().cid) //no class id ever used
- ;
- size_t bpp = _send_frame_size - hdr_size;
- return bpp/_send_otw_type.get_sample_size();
-}
-
-size_t usrp_e100_impl::send(
- const send_buffs_type &buffs, size_t nsamps_per_buff,
- const tx_metadata_t &metadata, const io_type_t &io_type,
- send_mode_t send_mode, double timeout
-){
- return _io_impl->send_handler.send(
- buffs, nsamps_per_buff,
- metadata, io_type,
- send_mode, timeout
- );
-}
-
-/***********************************************************************
- * Data Recv
- **********************************************************************/
-size_t usrp_e100_impl::get_max_recv_samps_per_packet(void) const{
- static const size_t hdr_size = 0
- + vrt::max_if_hdr_words32*sizeof(boost::uint32_t)
- + sizeof(vrt::if_packet_info_t().tlr) //forced to have trailer
- - sizeof(vrt::if_packet_info_t().cid) //no class id ever used
- ;
- size_t bpp = _recv_frame_size - hdr_size;
- return bpp/_recv_otw_type.get_sample_size();
-}
-
-size_t usrp_e100_impl::recv(
- const recv_buffs_type &buffs, size_t nsamps_per_buff,
- rx_metadata_t &metadata, const io_type_t &io_type,
- recv_mode_t recv_mode, double timeout
-){
- return _io_impl->recv_handler.recv(
- buffs, nsamps_per_buff,
- metadata, io_type,
- recv_mode, timeout
- );
-}
-
-/***********************************************************************
- * Async Recv
- **********************************************************************/
-bool usrp_e100_impl::recv_async_msg(
- async_metadata_t &async_metadata, double timeout
-){
- boost::this_thread::disable_interruption di; //disable because the wait can throw
- return _io_impl->async_msg_fifo.pop_with_timed_wait(async_metadata, timeout);
-}
diff --git a/host/lib/usrp/usrp_e100/mboard_impl.cpp b/host/lib/usrp/usrp_e100/mboard_impl.cpp
deleted file mode 100644
index f4b8d79f6..000000000
--- a/host/lib/usrp/usrp_e100/mboard_impl.cpp
+++ /dev/null
@@ -1,222 +0,0 @@
-//
-// Copyright 2010-2011 Ettus Research LLC
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// 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 "usrp_e100_impl.hpp"
-#include "usrp_e100_regs.hpp"
-#include <uhd/utils/msg.hpp>
-#include <uhd/exception.hpp>
-#include <uhd/usrp/dsp_utils.hpp>
-#include <uhd/usrp/misc_utils.hpp>
-#include <uhd/usrp/mboard_props.hpp>
-#include <boost/bind.hpp>
-
-using namespace uhd;
-using namespace uhd::usrp;
-
-/***********************************************************************
- * Mboard Initialization
- **********************************************************************/
-void usrp_e100_impl::mboard_init(void){
- _mboard_proxy = wax_obj_proxy::make(
- boost::bind(&usrp_e100_impl::mboard_get, this, _1, _2),
- boost::bind(&usrp_e100_impl::mboard_set, this, _1, _2)
- );
-
- //init the clock config
- _clock_config = clock_config_t::internal();
- update_clock_config();
-}
-
-void usrp_e100_impl::update_clock_config(void){
- boost::uint32_t pps_flags = 0;
-
- //translate pps polarity enums
- switch(_clock_config.pps_polarity){
- case clock_config_t::PPS_POS: pps_flags |= UE_FLAG_TIME64_PPS_POSEDGE; break;
- case clock_config_t::PPS_NEG: pps_flags |= UE_FLAG_TIME64_PPS_NEGEDGE; break;
- default: throw uhd::value_error("unhandled clock configuration pps polarity");
- }
-
- //set the pps flags
- _iface->poke32(UE_REG_TIME64_FLAGS, pps_flags);
-
- //clock source ref 10mhz
- switch(_clock_config.ref_source){
- case clock_config_t::REF_AUTO: _clock_ctrl->use_auto_ref(); break;
- case clock_config_t::REF_INT: _clock_ctrl->use_internal_ref(); break;
- case clock_config_t::REF_SMA: _clock_ctrl->use_auto_ref(); break;
- default: throw uhd::value_error("unhandled clock configuration ref source");
- }
-}
-
-/***********************************************************************
- * Mboard Get
- **********************************************************************/
-void usrp_e100_impl::mboard_get(const wax::obj &key_, wax::obj &val){
- named_prop_t key = named_prop_t::extract(key_);
-
- //handle the get request conditioned on the key
- switch(key.as<mboard_prop_t>()){
- case MBOARD_PROP_NAME:
- val = std::string("usrp-e mboard");
- return;
-
- case MBOARD_PROP_OTHERS:
- val = prop_names_t();
- return;
-
- case MBOARD_PROP_RX_DBOARD:
- UHD_ASSERT_THROW(key.name == "");
- val = _rx_dboard_proxy->get_link();
- return;
-
- case MBOARD_PROP_RX_DBOARD_NAMES:
- val = prop_names_t(1, ""); //vector of size 1 with empty string
- return;
-
- case MBOARD_PROP_TX_DBOARD:
- UHD_ASSERT_THROW(key.name == "");
- val = _tx_dboard_proxy->get_link();
- return;
-
- case MBOARD_PROP_TX_DBOARD_NAMES:
- val = prop_names_t(1, ""); //vector of size 1 with empty string
- return;
-
- case MBOARD_PROP_RX_DSP:
- UHD_ASSERT_THROW(key.name == "");
- val = _rx_ddc_proxy->get_link();
- return;
-
- case MBOARD_PROP_RX_DSP_NAMES:
- val = prop_names_t(1, "");
- return;
-
- case MBOARD_PROP_TX_DSP:
- UHD_ASSERT_THROW(key.name == "");
- val = _tx_duc_proxy->get_link();
- return;
-
- case MBOARD_PROP_TX_DSP_NAMES:
- val = prop_names_t(1, "");
- return;
-
- case MBOARD_PROP_CLOCK_CONFIG:
- val = _clock_config;
- return;
-
- case MBOARD_PROP_RX_SUBDEV_SPEC:
- val = _rx_subdev_spec;
- return;
-
- case MBOARD_PROP_TX_SUBDEV_SPEC:
- val = _tx_subdev_spec;
- return;
-
- case MBOARD_PROP_EEPROM_MAP:
- val = _iface->mb_eeprom;
- return;
-
- case MBOARD_PROP_TIME_NOW: while(true){
- uint32_t secs = _iface->peek32(UE_REG_RB_TIME_NOW_SECS);
- uint32_t ticks = _iface->peek32(UE_REG_RB_TIME_NOW_TICKS);
- if (secs != _iface->peek32(UE_REG_RB_TIME_NOW_SECS)) continue;
- val = time_spec_t(secs, ticks, _clock_ctrl->get_fpga_clock_rate());
- return;
- }
-
- case MBOARD_PROP_TIME_PPS: while(true){
- uint32_t secs = _iface->peek32(UE_REG_RB_TIME_PPS_SECS);
- uint32_t ticks = _iface->peek32(UE_REG_RB_TIME_PPS_TICKS);
- if (secs != _iface->peek32(UE_REG_RB_TIME_PPS_SECS)) continue;
- val = time_spec_t(secs, ticks, _clock_ctrl->get_fpga_clock_rate());
- return;
- }
-
- case MBOARD_PROP_CLOCK_RATE:
- val = _clock_ctrl->get_fpga_clock_rate();
- return;
-
- default: UHD_THROW_PROP_GET_ERROR();
- }
-}
-
-/***********************************************************************
- * Mboard Set
- **********************************************************************/
-void usrp_e100_impl::mboard_set(const wax::obj &key, const wax::obj &val){
- //handle the get request conditioned on the key
- switch(key.as<mboard_prop_t>()){
-
- case MBOARD_PROP_TIME_NOW:
- case MBOARD_PROP_TIME_PPS:{
- time_spec_t time_spec = val.as<time_spec_t>();
- _iface->poke32(UE_REG_TIME64_TICKS, time_spec.get_tick_count(_clock_ctrl->get_fpga_clock_rate()));
- boost::uint32_t imm_flags = (key.as<mboard_prop_t>() == MBOARD_PROP_TIME_NOW)? 1 : 0;
- _iface->poke32(UE_REG_TIME64_IMM, imm_flags);
- _iface->poke32(UE_REG_TIME64_SECS, time_spec.get_full_secs());
- }
- return;
-
- case MBOARD_PROP_RX_SUBDEV_SPEC:
- _rx_subdev_spec = val.as<subdev_spec_t>();
- verify_rx_subdev_spec(_rx_subdev_spec, _mboard_proxy->get_link());
- //sanity check
- UHD_ASSERT_THROW(_rx_subdev_spec.size() == 1);
- //set the mux
- _iface->poke32(UE_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>();
- verify_tx_subdev_spec(_tx_subdev_spec, _mboard_proxy->get_link());
- //sanity check
- UHD_ASSERT_THROW(_tx_subdev_spec.size() == 1);
- //set the mux
- _iface->poke32(UE_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;
-
- case MBOARD_PROP_EEPROM_MAP:
- // Step1: commit the map, writing only those values set.
- // Step2: readback the entire eeprom map into the iface.
- val.as<mboard_eeprom_t>().commit(_iface->get_i2c_dev_iface(), mboard_eeprom_t::MAP_E100);
- _iface->mb_eeprom = mboard_eeprom_t(_iface->get_i2c_dev_iface(), mboard_eeprom_t::MAP_E100);
- return;
-
- case MBOARD_PROP_CLOCK_CONFIG:
- _clock_config = val.as<clock_config_t>();
- update_clock_config();
- return;
-
- case MBOARD_PROP_CLOCK_RATE:
- UHD_MSG(warning)
- << "I see that you are setting the master clock rate from the API.\n"
- << "You may pass this into the device address as master_clock_rate=<rate>.\n"
- << "This way, the clock rate is guaranteed to be initialized first.\n"
- << "See the application notes for USRP-E1XX for further instructions.\n"
- ;
- _clock_ctrl->set_fpga_clock_rate(val.as<double>());
- this->update_xport_channel_mapping();
- return;
-
- default: UHD_THROW_PROP_SET_ERROR();
- }
-}
diff --git a/host/lib/usrp/usrp_e100/usrp_e100_iface.hpp b/host/lib/usrp/usrp_e100/usrp_e100_iface.hpp
deleted file mode 100644
index d9fe96db7..000000000
--- a/host/lib/usrp/usrp_e100/usrp_e100_iface.hpp
+++ /dev/null
@@ -1,75 +0,0 @@
-//
-// Copyright 2010-2011 Ettus Research LLC
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// 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_USRP_E100_IFACE_HPP
-#define INCLUDED_USRP_E100_IFACE_HPP
-
-#include <uhd/transport/udp_simple.hpp>
-#include <uhd/usrp/mboard_eeprom.hpp>
-#include <uhd/types/serial.hpp>
-#include <boost/shared_ptr.hpp>
-#include <boost/utility.hpp>
-#include <boost/cstdint.hpp>
-#include <uhd/usrp/mboard_iface.hpp>
-
-////////////////////////////////////////////////////////////////////////
-// 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)
-////////////////////////////////////////////////////////////////////////
-
-/*!
- * The usrp-e interface class:
- * Provides a set of functions to implementation layer.
- * Including spi, peek, poke, control...
- */
-class usrp_e100_iface : boost::noncopyable, public uhd::usrp::mboard_iface{
-public:
- typedef boost::shared_ptr<usrp_e100_iface> sptr;
-
- /*!
- * Make a new usrp-e interface with the control transport.
- * \param node the device node name
- * \return a new usrp-e interface object
- */
- static sptr make(const std::string &node);
-
- /*!
- * Get the underlying file descriptor.
- * \return the file descriptor
- */
- virtual int get_file_descriptor(void) = 0;
-
- /*!
- * Perform an ioctl call on the device node file descriptor.
- * This will throw when the internal ioctl call fails.
- * \param request the control word
- * \param mem pointer to some memory
- */
- virtual void ioctl(int request, void *mem) = 0;
-
- //! Get the I2C interface for the I2C device node
- virtual uhd::i2c_iface &get_i2c_dev_iface(void) = 0;
-
- //motherboard eeprom map structure
- uhd::usrp::mboard_eeprom_t mb_eeprom;
-};
-
-#endif /* INCLUDED_USRP_E100_IFACE_HPP */
diff --git a/host/lib/usrp/usrp_e100/usrp_e100_impl.cpp b/host/lib/usrp/usrp_e100/usrp_e100_impl.cpp
deleted file mode 100644
index ae0c0b1b7..000000000
--- a/host/lib/usrp/usrp_e100/usrp_e100_impl.cpp
+++ /dev/null
@@ -1,217 +0,0 @@
-//
-// Copyright 2010-2011 Ettus Research LLC
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// 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 "usrp_e100_impl.hpp"
-#include "usrp_e100_regs.hpp"
-#include <uhd/utils/msg.hpp>
-#include <uhd/usrp/device_props.hpp>
-#include <uhd/usrp/mboard_props.hpp>
-#include <uhd/exception.hpp>
-#include <uhd/utils/static.hpp>
-#include <uhd/utils/images.hpp>
-#include <boost/format.hpp>
-#include <boost/filesystem.hpp>
-#include <boost/functional/hash.hpp>
-#include <fstream>
-
-using namespace uhd;
-using namespace uhd::usrp;
-namespace fs = boost::filesystem;
-
-/***********************************************************************
- * Discovery
- **********************************************************************/
-static device_addrs_t usrp_e100_find(const device_addr_t &hint){
- device_addrs_t usrp_e100_addrs;
-
- //return an empty list of addresses when type is set to non-usrp-e
- if (hint.has_key("type") and hint["type"] != "e100") return usrp_e100_addrs;
-
- //device node not provided, assume its 0
- if (not hint.has_key("node")){
- device_addr_t new_addr = hint;
- new_addr["node"] = "/dev/usrp_e0";
- return usrp_e100_find(new_addr);
- }
-
- //use the given device node name
- if (fs::exists(hint["node"])){
- device_addr_t new_addr;
- new_addr["type"] = "usrp-e";
- new_addr["node"] = fs::system_complete(fs::path(hint["node"])).string();
- try{
- usrp_e100_iface::sptr iface = usrp_e100_iface::make(new_addr["node"]);
- new_addr["name"] = "";//FIXME for double open on next branch iface->mb_eeprom["name"];
- new_addr["serial"] = "";//FIXME for double open on next branch iface->mb_eeprom["serial"];
- }
- catch(const std::exception &e){
- new_addr["name"] = "";
- new_addr["serial"] = "";
- }
- if (
- (not hint.has_key("name") or hint["name"] == new_addr["name"]) and
- (not hint.has_key("serial") or hint["serial"] == new_addr["serial"])
- ){
- usrp_e100_addrs.push_back(new_addr);
- }
- }
-
- return usrp_e100_addrs;
-}
-
-/***********************************************************************
- * Make
- **********************************************************************/
-static size_t hash_fpga_file(const std::string &file_path){
- size_t hash = 0;
- std::ifstream file(file_path.c_str());
- if (not file.good()) throw uhd::io_error("cannot open fpga file for read: " + file_path);
- while (file.good()) boost::hash_combine(hash, file.get());
- file.close();
- return hash;
-}
-
-static device::sptr usrp_e100_make(const device_addr_t &device_addr){
-
- //setup the main interface into fpga
- std::string node = device_addr["node"];
- UHD_MSG(status) << boost::format("Opening USRP-E on %s") % node << std::endl;
- usrp_e100_iface::sptr iface = usrp_e100_iface::make(node);
-
- //extract the fpga path for usrp-e
- std::string usrp_e100_fpga_image = find_image_path(device_addr.get("fpga", "usrp_e100_fpga.bin"));
-
- //compute a hash of the fpga file
- const boost::uint32_t file_hash = boost::uint32_t(hash_fpga_file(usrp_e100_fpga_image));
-
- //When the hash does not match:
- // - unload the iface to free the node
- // - load the fpga configuration file
- // - re-open the iface on the node
- if (iface->peek32(UE_REG_RB_MISC_TEST32) != file_hash){
- iface.reset();
- usrp_e100_load_fpga(usrp_e100_fpga_image);
- sleep(1); ///\todo do this better one day.
- UHD_MSG(status) << boost::format("re-Opening USRP-E on %s") % node << std::endl;
- iface = usrp_e100_iface::make(node);
- }
-
- //store the hash into the FPGA register
- iface->poke32(UE_REG_SR_MISC_TEST32, file_hash);
-
- //check that the hash can be readback correctly
- if (iface->peek32(UE_REG_RB_MISC_TEST32) != file_hash){
- UHD_MSG(error) << boost::format(
- "The FPGA hash readback failed!\n"
- "The FPGA is either clocked improperly\n"
- "or the FPGA build is not compatible.\n"
- );
- }
-
- //check that the compatibility is correct
- const boost::uint16_t fpga_compat_num = iface->peek16(UE_REG_MISC_COMPAT);
- if (fpga_compat_num != USRP_E_FPGA_COMPAT_NUM){
- throw uhd::runtime_error(str(boost::format(
- "\nPlease update the FPGA image for your device.\n"
- "See the application notes for USRP E-Series for instructions.\n"
- "Expected FPGA compatibility number 0x%x, but got 0x%x:\n"
- "The FPGA build is not compatible with the host code build."
- ) % USRP_E_FPGA_COMPAT_NUM % fpga_compat_num));
- }
-
- return device::sptr(new usrp_e100_impl(iface, device_addr));
-}
-
-UHD_STATIC_BLOCK(register_usrp_e100_device){
- device::register_device(&usrp_e100_find, &usrp_e100_make);
-}
-
-/***********************************************************************
- * Structors
- **********************************************************************/
-usrp_e100_impl::usrp_e100_impl(
- usrp_e100_iface::sptr iface,
- const device_addr_t &device_addr
-):
- _iface(iface),
- _data_xport(usrp_e100_make_mmap_zero_copy(_iface)),
- _recv_frame_size(std::min(_data_xport->get_recv_frame_size(), size_t(device_addr.cast<double>("recv_frame_size", 1e9)))),
- _send_frame_size(std::min(_data_xport->get_send_frame_size(), size_t(device_addr.cast<double>("send_frame_size", 1e9))))
-{
-
- //setup interfaces into hardware
- const double master_clock_rate = device_addr.cast<double>("master_clock_rate", 64e6);
- _clock_ctrl = usrp_e100_clock_ctrl::make(_iface, master_clock_rate);
- _codec_ctrl = usrp_e100_codec_ctrl::make(_iface);
-
- //initialize the mboard
- mboard_init();
-
- //initialize the dboards
- dboard_init();
-
- //initialize the dsps
- rx_ddc_init();
- tx_duc_init();
-
- //init the codec properties
- codec_init();
-
- //set default subdev specs
- this->mboard_set(MBOARD_PROP_RX_SUBDEV_SPEC, subdev_spec_t());
- this->mboard_set(MBOARD_PROP_TX_SUBDEV_SPEC, subdev_spec_t());
-
- //init the io send/recv
- io_init();
-
-}
-
-usrp_e100_impl::~usrp_e100_impl(void){
- /* NOP */
-}
-
-/***********************************************************************
- * Device Get
- **********************************************************************/
-void usrp_e100_impl::get(const wax::obj &key_, wax::obj &val){
- named_prop_t key = named_prop_t::extract(key_);
-
- //handle the get request conditioned on the key
- switch(key.as<device_prop_t>()){
- case DEVICE_PROP_NAME:
- val = std::string("usrp-e device");
- return;
-
- case DEVICE_PROP_MBOARD:
- UHD_ASSERT_THROW(key.name == "");
- val = _mboard_proxy->get_link();
- return;
-
- case DEVICE_PROP_MBOARD_NAMES:
- val = prop_names_t(1, ""); //vector of size 1 with empty string
- return;
-
- default: UHD_THROW_PROP_GET_ERROR();
- }
-}
-
-/***********************************************************************
- * Device Set
- **********************************************************************/
-void usrp_e100_impl::set(const wax::obj &, const wax::obj &){
- UHD_THROW_PROP_SET_ERROR();
-}
diff --git a/host/lib/usrp/usrp_e100/usrp_e100_impl.hpp b/host/lib/usrp/usrp_e100/usrp_e100_impl.hpp
deleted file mode 100644
index 1c17863fb..000000000
--- a/host/lib/usrp/usrp_e100/usrp_e100_impl.hpp
+++ /dev/null
@@ -1,173 +0,0 @@
-//
-// Copyright 2010-2011 Ettus Research LLC
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// 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 "usrp_e100_iface.hpp"
-#include "clock_ctrl.hpp"
-#include "codec_ctrl.hpp"
-#include <uhd/device.hpp>
-#include <uhd/utils/pimpl.hpp>
-#include <uhd/usrp/subdev_spec.hpp>
-#include <uhd/usrp/dboard_eeprom.hpp>
-#include <uhd/types/otw_type.hpp>
-#include <uhd/types/clock_config.hpp>
-#include <uhd/types/stream_cmd.hpp>
-#include <uhd/usrp/dboard_manager.hpp>
-#include <uhd/transport/zero_copy.hpp>
-
-#ifndef INCLUDED_USRP_E100_IMPL_HPP
-#define INCLUDED_USRP_E100_IMPL_HPP
-
-uhd::transport::zero_copy_if::sptr usrp_e100_make_mmap_zero_copy(usrp_e100_iface::sptr iface);
-
-static const boost::uint16_t USRP_E_FPGA_COMPAT_NUM = 0x04;
-
-//! load an fpga image from a bin file into the usrp-e fpga
-extern void usrp_e100_load_fpga(const std::string &bin_file);
-
-/*!
- * Make a usrp-e dboard interface.
- * \param iface the usrp-e interface object
- * \param clock the clock control interface
- * \param codec the codec control interface
- * \return a sptr to a new dboard interface
- */
-uhd::usrp::dboard_iface::sptr make_usrp_e100_dboard_iface(
- usrp_e100_iface::sptr iface,
- usrp_e100_clock_ctrl::sptr clock,
- usrp_e100_codec_ctrl::sptr codec
-);
-
-/*!
- * Simple wax obj proxy class:
- * Provides a wax obj interface for a set and a get function.
- * This allows us to create nested properties structures
- * while maintaining flattened code within the implementation.
- */
-class wax_obj_proxy : public wax::obj{
-public:
- typedef boost::function<void(const wax::obj &, wax::obj &)> get_t;
- typedef boost::function<void(const wax::obj &, const wax::obj &)> set_t;
- typedef boost::shared_ptr<wax_obj_proxy> sptr;
-
- static sptr make(const get_t &get, const set_t &set){
- return sptr(new wax_obj_proxy(get, set));
- }
-
-private:
- get_t _get; set_t _set;
- wax_obj_proxy(const get_t &get, const set_t &set): _get(get), _set(set){};
- void get(const wax::obj &key, wax::obj &val){return _get(key, val);}
- void set(const wax::obj &key, const wax::obj &val){return _set(key, val);}
-};
-
-/*!
- * USRP-E100 implementation guts:
- * The implementation details are encapsulated here.
- * Handles properties on the mboard, dboard, dsps...
- */
-class usrp_e100_impl : public uhd::device{
-public:
- //structors
- usrp_e100_impl(usrp_e100_iface::sptr, const uhd::device_addr_t &);
- ~usrp_e100_impl(void);
-
- //the io interface
- size_t send(const send_buffs_type &, size_t, const uhd::tx_metadata_t &, const uhd::io_type_t &, send_mode_t, double);
- size_t recv(const recv_buffs_type &, size_t, uhd::rx_metadata_t &, const uhd::io_type_t &, recv_mode_t, double);
- bool recv_async_msg(uhd::async_metadata_t &, double);
- size_t get_max_send_samps_per_packet(void) const;
- size_t get_max_recv_samps_per_packet(void) const;
-
-private:
- //interface to ioctls and file descriptor
- usrp_e100_iface::sptr _iface;
-
- //handle io stuff
- uhd::transport::zero_copy_if::sptr _data_xport;
- UHD_PIMPL_DECL(io_impl) _io_impl;
- size_t _recv_frame_size, _send_frame_size;
- uhd::otw_type_t _send_otw_type, _recv_otw_type;
- void io_init(void);
- void issue_stream_cmd(const uhd::stream_cmd_t &stream_cmd);
- void handle_overrun(size_t);
- void update_xport_channel_mapping(void);
-
- //configuration shadows
- uhd::clock_config_t _clock_config;
-
- //ad9522 clock control
- usrp_e100_clock_ctrl::sptr _clock_ctrl;
-
- //ad9862 codec control
- usrp_e100_codec_ctrl::sptr _codec_ctrl;
-
- //device functions and settings
- void get(const wax::obj &, wax::obj &);
- void set(const wax::obj &, const wax::obj &);
-
- //mboard functions and settings
- void mboard_init(void);
- void mboard_get(const wax::obj &, wax::obj &);
- void mboard_set(const wax::obj &, const wax::obj &);
- wax_obj_proxy::sptr _mboard_proxy;
- uhd::usrp::subdev_spec_t _rx_subdev_spec, _tx_subdev_spec;
-
- //xx dboard functions and settings
- void dboard_init(void);
- uhd::usrp::dboard_manager::sptr _dboard_manager;
- uhd::usrp::dboard_iface::sptr _dboard_iface;
-
- //rx dboard functions and settings
- uhd::usrp::dboard_eeprom_t _rx_db_eeprom;
- 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;
-
- //tx dboard functions and settings
- uhd::usrp::dboard_eeprom_t _tx_db_eeprom, _gdb_eeprom;
- 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;
-
- //rx ddc functions and settings
- void rx_ddc_init(void);
- void rx_ddc_get(const wax::obj &, wax::obj &);
- void rx_ddc_set(const wax::obj &, const wax::obj &);
- double _ddc_freq; size_t _ddc_decim;
- wax_obj_proxy::sptr _rx_ddc_proxy;
-
- //tx duc functions and settings
- void tx_duc_init(void);
- void tx_duc_get(const wax::obj &, wax::obj &);
- void tx_duc_set(const wax::obj &, const wax::obj &);
- double _duc_freq; size_t _duc_interp;
- wax_obj_proxy::sptr _tx_duc_proxy;
-
- //codec functions and settings
- 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, _tx_codec_proxy;
-
- //clock control functions and settings
- void init_clock_config(void);
- void update_clock_config(void);
-};
-
-#endif /* INCLUDED_USRP_E100_IMPL_HPP */
diff --git a/host/lib/usrp/usrp_e100/usrp_e100_regs.hpp b/host/lib/usrp/usrp_e100/usrp_e100_regs.hpp
deleted file mode 100644
index 1bcae64c7..000000000
--- a/host/lib/usrp/usrp_e100/usrp_e100_regs.hpp
+++ /dev/null
@@ -1,221 +0,0 @@
-
-
-////////////////////////////////////////////////////////////////
-//
-// Memory map for embedded wishbone bus
-//
-////////////////////////////////////////////////////////////////
-
-// All addresses are byte addresses. All accesses are word (16-bit) accesses.
-// This means that address bit 0 is usually 0.
-// There are 11 bits of address for the control.
-
-#ifndef INCLUDED_USRP_E100_REGS_HPP
-#define INCLUDED_USRP_E100_REGS_HPP
-
-/////////////////////////////////////////////////////
-// Slave pointers
-
-#define UE_REG_SLAVE(n) ((n)<<7)
-
-/////////////////////////////////////////////////////
-// Slave 0 -- Misc Regs
-
-#define UE_REG_MISC_BASE UE_REG_SLAVE(0)
-
-#define UE_REG_MISC_LED UE_REG_MISC_BASE + 0
-#define UE_REG_MISC_SW UE_REG_MISC_BASE + 2
-#define UE_REG_MISC_CGEN_CTRL UE_REG_MISC_BASE + 4
-#define UE_REG_MISC_CGEN_ST UE_REG_MISC_BASE + 6
-#define UE_REG_MISC_TEST UE_REG_MISC_BASE + 8
-#define UE_REG_MISC_RX_LEN UE_REG_MISC_BASE + 10
-#define UE_REG_MISC_TX_LEN UE_REG_MISC_BASE + 12
-#define UE_REG_MISC_XFER_RATE UE_REG_MISC_BASE + 14
-#define UE_REG_MISC_COMPAT UE_REG_MISC_BASE + 16
-
-/////////////////////////////////////////////////////
-// Slave 1 -- UART
-// CLKDIV is 16 bits, others are only 8
-
-#define UE_REG_UART_BASE UE_REG_SLAVE(1)
-
-#define UE_REG_UART_CLKDIV UE_REG_UART_BASE + 0
-#define UE_REG_UART_TXLEVEL UE_REG_UART_BASE + 2
-#define UE_REG_UART_RXLEVEL UE_REG_UART_BASE + 4
-#define UE_REG_UART_TXCHAR UE_REG_UART_BASE + 6
-#define UE_REG_UART_RXCHAR UE_REG_UART_BASE + 8
-
-/////////////////////////////////////////////////////
-// Slave 2 -- SPI Core
-// This should be accessed through the IOCTL
-// Users should not touch directly
-
-#define UE_REG_SPI_BASE UE_REG_SLAVE(2)
-
-//spi slave constants
-#define UE_SPI_SS_AD9522 (1 << 3)
-#define UE_SPI_SS_AD9862 (1 << 2)
-#define UE_SPI_SS_TX_DB (1 << 1)
-#define UE_SPI_SS_RX_DB (1 << 0)
-
-////////////////////////////////////////////////
-// Slave 3 -- I2C Core
-// This should be accessed through the IOCTL
-// Users should not touch directly
-
-#define UE_REG_I2C_BASE UE_REG_SLAVE(3)
-
-
-////////////////////////////////////////////////
-// Slave 4 -- GPIO
-
-#define UE_REG_GPIO_BASE UE_REG_SLAVE(4)
-
-#define UE_REG_GPIO_RX_IO UE_REG_GPIO_BASE + 0
-#define UE_REG_GPIO_TX_IO UE_REG_GPIO_BASE + 2
-#define UE_REG_GPIO_RX_DDR UE_REG_GPIO_BASE + 4
-#define UE_REG_GPIO_TX_DDR UE_REG_GPIO_BASE + 6
-#define UE_REG_GPIO_RX_SEL UE_REG_GPIO_BASE + 8
-#define UE_REG_GPIO_TX_SEL UE_REG_GPIO_BASE + 10
-#define UE_REG_GPIO_RX_DBG UE_REG_GPIO_BASE + 12
-#define UE_REG_GPIO_TX_DBG UE_REG_GPIO_BASE + 14
-
-//possible bit values for sel when dbg is 0:
-#define GPIO_SEL_SW 0 // if pin is an output, set by software in the io reg
-#define GPIO_SEL_ATR 1 // if pin is an output, set by ATR logic
-
-//possible bit values for sel when dbg is 1:
-#define GPIO_SEL_DEBUG_0 0 // if pin is an output, debug lines from FPGA fabric
-#define GPIO_SEL_DEBUG_1 1 // if pin is an output, debug lines from FPGA fabric
-
-///////////////////////////////////////////////////
-// Slave 6 -- ATR Controller
-// 16 regs
-
-#define UE_REG_ATR_BASE UE_REG_SLAVE(6)
-
-#define UE_REG_ATR_IDLE_RXSIDE UE_REG_ATR_BASE + 0
-#define UE_REG_ATR_IDLE_TXSIDE UE_REG_ATR_BASE + 2
-#define UE_REG_ATR_INTX_RXSIDE UE_REG_ATR_BASE + 4
-#define UE_REG_ATR_INTX_TXSIDE UE_REG_ATR_BASE + 6
-#define UE_REG_ATR_INRX_RXSIDE UE_REG_ATR_BASE + 8
-#define UE_REG_ATR_INRX_TXSIDE UE_REG_ATR_BASE + 10
-#define UE_REG_ATR_FULL_RXSIDE UE_REG_ATR_BASE + 12
-#define UE_REG_ATR_FULL_TXSIDE UE_REG_ATR_BASE + 14
-
-///////////////////////////////////////////////////
-// Slave 7 -- Readback Mux 32
-
-#define UE_REG_RB_MUX_32_BASE UE_REG_SLAVE(7)
-
-#define UE_REG_RB_TIME_NOW_SECS UE_REG_RB_MUX_32_BASE + 0
-#define UE_REG_RB_TIME_NOW_TICKS UE_REG_RB_MUX_32_BASE + 4
-#define UE_REG_RB_TIME_PPS_SECS UE_REG_RB_MUX_32_BASE + 8
-#define UE_REG_RB_TIME_PPS_TICKS UE_REG_RB_MUX_32_BASE + 12
-#define UE_REG_RB_MISC_TEST32 UE_REG_RB_MUX_32_BASE + 16
-
-////////////////////////////////////////////////////
-// Slave 8 -- Settings Bus
-//
-// Output-only, no readback, 64 registers total
-// Each register must be written 64 bits at a time
-// First the address xxx_xx00 and then xxx_xx10
-
-#define UE_REG_SETTINGS_BASE_ADDR(n) (UE_REG_SLAVE(8) + (4*(n)))
-
-#define UE_REG_SR_MISC_TEST32 UE_REG_SETTINGS_BASE_ADDR(52)
-
-/////////////////////////////////////////////////
-// Magic reset regs
-////////////////////////////////////////////////
-#define UE_REG_CLEAR_ADDR(n) (UE_REG_SETTINGS_BASE_ADDR(48) + (4*(n)))
-#define UE_REG_CLEAR_RX UE_REG_CLEAR_ADDR(0)
-#define UE_REG_CLEAR_TX UE_REG_CLEAR_ADDR(1)
-
-/////////////////////////////////////////////////
-// DSP RX Regs
-////////////////////////////////////////////////
-#define UE_REG_DSP_RX_ADDR(n) (UE_REG_SETTINGS_BASE_ADDR(16) + (4*(n)))
-#define UE_REG_DSP_RX_FREQ UE_REG_DSP_RX_ADDR(0)
-#define UE_REG_DSP_RX_SCALE_IQ UE_REG_DSP_RX_ADDR(1) // {scale_i,scale_q}
-#define UE_REG_DSP_RX_DECIM_RATE UE_REG_DSP_RX_ADDR(2) // hb and decim rate
-#define UE_REG_DSP_RX_DCOFFSET_I UE_REG_DSP_RX_ADDR(3) // Bit 31 high sets fixed offset mode, using lower 14 bits, // otherwise it is automatic
-#define UE_REG_DSP_RX_DCOFFSET_Q UE_REG_DSP_RX_ADDR(4) // Bit 31 high sets fixed offset mode, using lower 14 bits
-#define UE_REG_DSP_RX_MUX UE_REG_DSP_RX_ADDR(5)
-
-///////////////////////////////////////////////////
-// VITA RX CTRL regs
-///////////////////////////////////////////////////
-#define UE_REG_CTRL_RX_ADDR(n) (UE_REG_SETTINGS_BASE_ADDR(0) + (4*(n)))
-// The following 3 are logically a single command register.
-// They are clocked into the underlying fifo when time_ticks is written.
-#define UE_REG_CTRL_RX_STREAM_CMD UE_REG_CTRL_RX_ADDR(0) // {now, chain, num_samples(30)
-#define UE_REG_CTRL_RX_TIME_SECS UE_REG_CTRL_RX_ADDR(1)
-#define UE_REG_CTRL_RX_TIME_TICKS UE_REG_CTRL_RX_ADDR(2)
-#define UE_REG_CTRL_RX_CLEAR UE_REG_CTRL_RX_ADDR(3) // write anything to clear
-#define UE_REG_CTRL_RX_VRT_HEADER UE_REG_CTRL_RX_ADDR(4) // word 0 of packet. FPGA fills in packet counter
-#define UE_REG_CTRL_RX_VRT_STREAM_ID UE_REG_CTRL_RX_ADDR(5) // word 1 of packet.
-#define UE_REG_CTRL_RX_VRT_TRAILER UE_REG_CTRL_RX_ADDR(6)
-#define UE_REG_CTRL_RX_NSAMPS_PER_PKT UE_REG_CTRL_RX_ADDR(7)
-#define UE_REG_CTRL_RX_NCHANNELS UE_REG_CTRL_RX_ADDR(8) // 1 in basic case, up to 4 for vector sources
-
-/////////////////////////////////////////////////
-// DSP TX Regs
-////////////////////////////////////////////////
-#define UE_REG_DSP_TX_ADDR(n) (UE_REG_SETTINGS_BASE_ADDR(32) + (4*(n)))
-#define UE_REG_DSP_TX_FREQ UE_REG_DSP_TX_ADDR(0)
-#define UE_REG_DSP_TX_SCALE_IQ UE_REG_DSP_TX_ADDR(1) // {scale_i,scale_q}
-#define UE_REG_DSP_TX_INTERP_RATE UE_REG_DSP_TX_ADDR(2)
-#define UE_REG_DSP_TX_UNUSED UE_REG_DSP_TX_ADDR(3)
-#define UE_REG_DSP_TX_MUX UE_REG_DSP_TX_ADDR(4)
-
-/////////////////////////////////////////////////
-// VITA TX CTRL regs
-////////////////////////////////////////////////
-#define UE_REG_CTRL_TX_ADDR(n) (UE_REG_SETTINGS_BASE_ADDR(24) + (4*(n)))
-#define UE_REG_CTRL_TX_NCHANNELS UE_REG_CTRL_TX_ADDR(0)
-#define UE_REG_CTRL_TX_CLEAR UE_REG_CTRL_TX_ADDR(1)
-#define UE_REG_CTRL_TX_REPORT_SID UE_REG_CTRL_TX_ADDR(2)
-#define UE_REG_CTRL_TX_POLICY UE_REG_CTRL_TX_ADDR(3)
-
-#define UE_FLAG_CTRL_TX_POLICY_WAIT (0x1 << 0)
-#define UE_FLAG_CTRL_TX_POLICY_NEXT_PACKET (0x1 << 1)
-#define UE_FLAG_CTRL_TX_POLICY_NEXT_BURST (0x1 << 2)
-
-/////////////////////////////////////////////////
-// VITA49 64 bit time (write only)
-////////////////////////////////////////////////
- /*!
- * \brief Time 64 flags
- *
- * <pre>
- *
- * 3 2 1
- * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
- * +-----------------------------------------------------------+-+-+
- * | |S|P|
- * +-----------------------------------------------------------+-+-+
- *
- * P - PPS edge selection (0=negedge, 1=posedge, default=0)
- * S - Source (0=sma, 1=mimo, 0=default)
- *
- * </pre>
- */
-#define UE_REG_TIME64_ADDR(n) (UE_REG_SETTINGS_BASE_ADDR(40) + (4*(n)))
-#define UE_REG_TIME64_SECS UE_REG_TIME64_ADDR(0) // value to set absolute secs to on next PPS
-#define UE_REG_TIME64_TICKS UE_REG_TIME64_ADDR(1) // value to set absolute ticks to on next PPS
-#define UE_REG_TIME64_FLAGS UE_REG_TIME64_ADDR(2) // flags - see chart above
-#define UE_REG_TIME64_IMM UE_REG_TIME64_ADDR(3) // set immediate (0=latch on next pps, 1=latch immediate, default=0)
-#define UE_REG_TIME64_TPS UE_REG_TIME64_ADDR(4) // clock ticks per second (counter rollover)
-
-//pps flags (see above)
-#define UE_FLAG_TIME64_PPS_NEGEDGE (0 << 0)
-#define UE_FLAG_TIME64_PPS_POSEDGE (1 << 0)
-#define UE_FLAG_TIME64_PPS_SMA (0 << 1)
-#define UE_FLAG_TIME64_PPS_MIMO (1 << 1)
-
-#define UE_FLAG_TIME64_LATCH_NOW 1
-#define UE_FLAG_TIME64_LATCH_NEXT_PPS 0
-
-#endif
-
diff --git a/host/lib/utils/CMakeLists.txt b/host/lib/utils/CMakeLists.txt
index c8268c7b0..fd3249099 100644
--- a/host/lib/utils/CMakeLists.txt
+++ b/host/lib/utils/CMakeLists.txt
@@ -136,5 +136,6 @@ LIBUHD_APPEND_SOURCES(
${CMAKE_CURRENT_SOURCE_DIR}/paths.cpp
${CMAKE_CURRENT_SOURCE_DIR}/props.cpp
${CMAKE_CURRENT_SOURCE_DIR}/static.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/tasks.cpp
${CMAKE_CURRENT_SOURCE_DIR}/thread_priority.cpp
)
diff --git a/host/lib/utils/tasks.cpp b/host/lib/utils/tasks.cpp
new file mode 100644
index 000000000..ef56bb2de
--- /dev/null
+++ b/host/lib/utils/tasks.cpp
@@ -0,0 +1,75 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// 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/tasks.hpp>
+#include <uhd/utils/msg.hpp>
+#include <boost/thread/thread.hpp>
+#include <boost/thread/barrier.hpp>
+#include <exception>
+#include <iostream>
+
+using namespace uhd;
+
+class task_impl : public task{
+public:
+
+ task_impl(const task_fcn_type &task_fcn){
+ boost::barrier spawn_barrier(2);
+ _thread_group.create_thread(boost::bind(&task_impl::task_loop, this, task_fcn, boost::ref(spawn_barrier)));
+ spawn_barrier.wait();
+ }
+
+ ~task_impl(void){
+ _thread_group.interrupt_all();
+ _thread_group.join_all();
+ }
+
+private:
+
+ void task_loop(const task_fcn_type &task_fcn, boost::barrier &spawn_barrier){
+ spawn_barrier.wait();
+
+ try{
+ while (not boost::this_thread::interruption_requested()){
+ task_fcn();
+ }
+ }
+ catch(const boost::thread_interrupted &){
+ //this is an ok way to exit the task loop
+ }
+ catch(const std::exception &e){
+ do_error_msg(e.what());
+ }
+ catch(...){
+ do_error_msg("unknown exception");
+ }
+ }
+
+ void do_error_msg(const std::string &msg){
+ UHD_MSG(error)
+ << "An unexpected exception was caught in a task loop." << std::endl
+ << "The task loop will now exit, things may not work." << std::endl
+ << msg << std::endl
+ ;
+ }
+
+ boost::thread_group _thread_group;
+};
+
+task::sptr task::make(const task_fcn_type &task_fcn){
+ return task::sptr(new task_impl(task_fcn));
+}
diff --git a/host/tests/CMakeLists.txt b/host/tests/CMakeLists.txt
index b7bcfb7d5..c97116233 100644
--- a/host/tests/CMakeLists.txt
+++ b/host/tests/CMakeLists.txt
@@ -27,12 +27,12 @@ SET(test_sources
error_test.cpp
gain_group_test.cpp
msg_test.cpp
+ property_test.cpp
ranges_test.cpp
sph_recv_test.cpp
sph_send_test.cpp
subdev_spec_test.cpp
time_spec_test.cpp
- tune_helper_test.cpp
vrt_test.cpp
wax_test.cpp
)
diff --git a/host/tests/property_test.cpp b/host/tests/property_test.cpp
new file mode 100644
index 000000000..04d3a831c
--- /dev/null
+++ b/host/tests/property_test.cpp
@@ -0,0 +1,175 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// 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/property_tree.hpp>
+#include <boost/bind.hpp>
+#include <exception>
+#include <iostream>
+
+struct coercer_type{
+ int doit(int x){
+ return x & ~0x3;
+ }
+};
+
+struct setter_type{
+ void doit(int x){
+ _x = x;
+ }
+
+ int _x;
+};
+
+struct getter_type{
+ int doit(void){
+ return _x;
+ }
+
+ int _x;
+};
+
+BOOST_AUTO_TEST_CASE(test_prop_simple){
+ uhd::property_tree::sptr tree = uhd::property_tree::make();
+ uhd::property<int> &prop = tree->create<int>("/");
+
+ BOOST_CHECK(prop.empty());
+ prop.set(0);
+ BOOST_CHECK(not prop.empty());
+
+ prop.set(42);
+ BOOST_CHECK_EQUAL(prop.get(), 42);
+ prop.set(34);
+ BOOST_CHECK_EQUAL(prop.get(), 34);
+}
+
+BOOST_AUTO_TEST_CASE(test_prop_with_subscriber){
+ uhd::property_tree::sptr tree = uhd::property_tree::make();
+ uhd::property<int> &prop = tree->create<int>("/");
+
+ setter_type setter;
+ prop.subscribe(boost::bind(&setter_type::doit, &setter, _1));
+
+ prop.set(42);
+ BOOST_CHECK_EQUAL(prop.get(), 42);
+ BOOST_CHECK_EQUAL(setter._x, 42);
+
+ prop.set(34);
+ BOOST_CHECK_EQUAL(prop.get(), 34);
+ BOOST_CHECK_EQUAL(setter._x, 34);
+}
+
+BOOST_AUTO_TEST_CASE(test_prop_with_publisher){
+ uhd::property_tree::sptr tree = uhd::property_tree::make();
+ uhd::property<int> &prop = tree->create<int>("/");
+
+ BOOST_CHECK(prop.empty());
+ getter_type getter;
+ prop.publish(boost::bind(&getter_type::doit, &getter));
+ BOOST_CHECK(not prop.empty());
+
+ getter._x = 42;
+ prop.set(0); //should not change
+ BOOST_CHECK_EQUAL(prop.get(), 42);
+
+ getter._x = 34;
+ prop.set(0); //should not change
+ BOOST_CHECK_EQUAL(prop.get(), 34);
+}
+
+BOOST_AUTO_TEST_CASE(test_prop_with_publisher_and_subscriber){
+ uhd::property_tree::sptr tree = uhd::property_tree::make();
+ uhd::property<int> &prop = tree->create<int>("/");
+
+ getter_type getter;
+ prop.publish(boost::bind(&getter_type::doit, &getter));
+
+ setter_type setter;
+ prop.subscribe(boost::bind(&setter_type::doit, &setter, _1));
+
+ getter._x = 42;
+ prop.set(0);
+ BOOST_CHECK_EQUAL(prop.get(), 42);
+ BOOST_CHECK_EQUAL(setter._x, 0);
+
+ getter._x = 34;
+ prop.set(1);
+ BOOST_CHECK_EQUAL(prop.get(), 34);
+ BOOST_CHECK_EQUAL(setter._x, 1);
+}
+
+BOOST_AUTO_TEST_CASE(test_prop_with_coercion){
+ uhd::property_tree::sptr tree = uhd::property_tree::make();
+ uhd::property<int> &prop = tree->create<int>("/");
+
+ setter_type setter;
+ prop.subscribe(boost::bind(&setter_type::doit, &setter, _1));
+
+ coercer_type coercer;
+ prop.coerce(boost::bind(&coercer_type::doit, &coercer, _1));
+
+ prop.set(42);
+ BOOST_CHECK_EQUAL(prop.get(), 40);
+ BOOST_CHECK_EQUAL(setter._x, 40);
+
+ prop.set(34);
+ BOOST_CHECK_EQUAL(prop.get(), 32);
+ BOOST_CHECK_EQUAL(setter._x, 32);
+}
+
+BOOST_AUTO_TEST_CASE(test_prop_tree){
+ uhd::property_tree::sptr tree = uhd::property_tree::make();
+
+ tree->create<int>("/test/prop0");
+ tree->create<int>("/test/prop1");
+
+ BOOST_CHECK(tree->exists("/test"));
+ BOOST_CHECK_THROW(tree->access<int>("/test"), std::exception);
+ BOOST_CHECK(tree->exists("/test/prop0"));
+ BOOST_CHECK(tree->exists("/test/prop1"));
+
+ tree->access<int>("/test/prop0").set(42);
+ tree->access<int>("/test/prop1").set(34);
+
+ BOOST_CHECK_EQUAL(tree->access<int>("/test/prop0").get(), 42);
+ BOOST_CHECK_EQUAL(tree->access<int>("/test/prop1").get(), 34);
+
+ tree->remove("/test/prop0");
+ BOOST_CHECK(not tree->exists("/test/prop0"));
+ BOOST_CHECK(tree->exists("/test/prop1"));
+
+ tree->remove("/test");
+ BOOST_CHECK(not tree->exists("/test/prop0"));
+ BOOST_CHECK(not tree->exists("/test/prop1"));
+
+}
+
+BOOST_AUTO_TEST_CASE(test_prop_subtree){
+ uhd::property_tree::sptr tree = uhd::property_tree::make();
+ tree->create<int>("/subdir1/subdir2");
+
+ uhd::property_tree::sptr subtree1 = tree->subtree("/");
+ const std::vector<std::string> tree_dirs1 = tree->list("/");
+ const std::vector<std::string> subtree1_dirs = subtree1->list("");
+ BOOST_CHECK_EQUAL_COLLECTIONS(tree_dirs1.begin(), tree_dirs1.end(), subtree1_dirs.begin(), subtree1_dirs.end());
+
+ uhd::property_tree::sptr subtree2 = subtree1->subtree("subdir1");
+ const std::vector<std::string> tree_dirs2 = tree->list("/subdir1");
+ const std::vector<std::string> subtree2_dirs = subtree2->list("");
+ BOOST_CHECK_EQUAL_COLLECTIONS(tree_dirs2.begin(), tree_dirs2.end(), subtree2_dirs.begin(), subtree2_dirs.end());
+
+}
diff --git a/host/tests/sph_recv_test.cpp b/host/tests/sph_recv_test.cpp
index cd33452c6..1387e3b66 100644
--- a/host/tests/sph_recv_test.cpp
+++ b/host/tests/sph_recv_test.cpp
@@ -290,6 +290,7 @@ BOOST_AUTO_TEST_CASE(test_sph_recv_one_channel_inline_message){
//generate a bunch of packets
for (size_t i = 0; i < NUM_PKTS_TO_TEST; i++){
+ ifpi.packet_type = uhd::transport::vrt::if_packet_info_t::PACKET_TYPE_DATA;
ifpi.num_payload_words32 = 10 + i%10;
dummy_recv_xport.push_back_packet(ifpi);
ifpi.packet_count++;
@@ -300,8 +301,6 @@ BOOST_AUTO_TEST_CASE(test_sph_recv_one_channel_inline_message){
ifpi.packet_type = uhd::transport::vrt::if_packet_info_t::PACKET_TYPE_EXTENSION;
ifpi.num_payload_words32 = 1;
dummy_recv_xport.push_back_packet(ifpi, uhd::rx_metadata_t::ERROR_CODE_OVERFLOW);
- ifpi.packet_count++;
- ifpi.packet_type = uhd::transport::vrt::if_packet_info_t::PACKET_TYPE_DATA;
}
}
diff --git a/host/tests/tune_helper_test.cpp b/host/tests/tune_helper_test.cpp
deleted file mode 100644
index 9147cd310..000000000
--- a/host/tests/tune_helper_test.cpp
+++ /dev/null
@@ -1,251 +0,0 @@
-//
-// Copyright 2010-2011 Ettus Research LLC
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// 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 <uhd/usrp/dsp_utils.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_subdev_bw : public wax::obj{
-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 = true;
- return;
-
- case SUBDEV_PROP_BANDWIDTH:
- val = _bandwidth;
- 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 = val.as<double>();
- return;
-
- case SUBDEV_PROP_BANDWIDTH:
- _bandwidth = val.as<double>();
- return;
-
- default: UHD_THROW_PROP_SET_ERROR();
- }
- }
-
- double _freq, _bandwidth;
-};
-
-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){
- named_prop_t key = named_prop_t::extract(key_);
- switch(key.as<dsp_prop_t>()){
- case DSP_PROP_CODEC_RATE:
- val = _codec_rate;
- return;
-
- case DSP_PROP_HOST_RATE:
- val = _host_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){
- named_prop_t key = named_prop_t::extract(key_);
- switch(key.as<dsp_prop_t>()){
- case DSP_PROP_FREQ_SHIFT:
- _freq_shift = val.as<double>();
- dsp_type1::calc_cordic_word_and_update(_freq_shift, _codec_rate);
- return;
-
- case DSP_PROP_HOST_RATE:
- _host_rate = val.as<double>();
- return;
-
- default: UHD_THROW_PROP_SET_ERROR();
- }
- }
-
- double _codec_rate, _freq_shift, _host_rate;
-};
-
-/***********************************************************************
- * 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 IF 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_rf_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 IF 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_rf_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_rf_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);
-}
-
-BOOST_AUTO_TEST_CASE(test_tune_helper_rx_lo_off){
- dummy_subdev_bw subdev;
- dummy_dsp dsp(100e6);
- tune_result_t tr;
-
- std::cout << "Testing tune helper RX automatic LO offset B >> fs" << std::endl;
- subdev[SUBDEV_PROP_BANDWIDTH] = double(40e6);
- dsp[DSP_PROP_HOST_RATE] = double(4e6);
- tr = tune_rx_subdev_and_dsp(subdev.get_link(), dsp.get_link(), 2.45e9);
- std::cout << tr.to_pp_string() << std::endl;
- BOOST_CHECK_CLOSE(tr.actual_rf_freq, 2.45e9+4e6/2, tolerance);
-
- std::cout << "Testing tune helper RX automatic LO offset B > fs" << std::endl;
- subdev[SUBDEV_PROP_BANDWIDTH] = double(40e6);
- dsp[DSP_PROP_HOST_RATE] = double(25e6);
- tr = tune_rx_subdev_and_dsp(subdev.get_link(), dsp.get_link(), 2.45e9);
- std::cout << tr.to_pp_string() << std::endl;
- BOOST_CHECK_CLOSE(tr.actual_rf_freq, 2.45e9+(40e6-25e6)/2, tolerance);
-
- std::cout << "Testing tune helper RX automatic LO offset B < fs" << std::endl;
- subdev[SUBDEV_PROP_BANDWIDTH] = double(20e6);
- dsp[DSP_PROP_HOST_RATE] = double(25e6);
- tr = tune_rx_subdev_and_dsp(subdev.get_link(), dsp.get_link(), 2.45e9);
- std::cout << tr.to_pp_string() << std::endl;
- BOOST_CHECK_CLOSE(tr.actual_rf_freq, 2.45e9, tolerance);
-}
diff --git a/host/usrp_e_utils/CMakeLists.txt b/host/usrp_e_utils/CMakeLists.txt
index e7d6ae4b8..9162a2099 100644
--- a/host/usrp_e_utils/CMakeLists.txt
+++ b/host/usrp_e_utils/CMakeLists.txt
@@ -23,19 +23,15 @@ LIBUHD_REGISTER_COMPONENT("USRP-E Utils" ENABLE_USRP_E_UTILS OFF "LINUX" OFF)
IF(ENABLE_USRP_E_UTILS)
ENABLE_LANGUAGE(C)
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR})
- INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/lib/usrp/usrp_e100)
- INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/lib/usrp/usrp_e100/include)
- INCLUDE_DIRECTORIES(${CMAKE_BINARY_DIR}/lib/ic_reg_maps)
+ INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/lib/usrp/e100)
+ INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/lib/usrp/e100/include)
SET(usrp_e_utils_sources
- usrp-e-utility.cpp
usrp-e-loopback.c
usrp-e-timed.c
usrp-e-wb-test.cpp
usrp-e-debug-pins.c
usrp-e-gpio.c
- usrp-e-i2c.c
- usrp-e-spi.c
)
#for each source: build an executable and install
diff --git a/host/usrp_e_utils/clkgen_config.hpp b/host/usrp_e_utils/clkgen_config.hpp
deleted file mode 100644
index f39f8bb19..000000000
--- a/host/usrp_e_utils/clkgen_config.hpp
+++ /dev/null
@@ -1,305 +0,0 @@
-//
-// Copyright 2011 Ettus Research LLC
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// 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 USRP_E_UTILS_CLKGEN_CONFIG_HPP
-#define USRP_E_UTILS_CLKGEN_CONFIG_HPP
-
-#include <iostream>
-#include <sstream>
-#include <fstream>
-#include <string>
-#include <cstdlib>
-
-#include <fcntl.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/ioctl.h>
-
-#include <linux/spi/spidev.h>
-
-namespace usrp_e_clkgen_config_utility{
-
-// Programming data for clock gen chip
-static const unsigned int config_data[] = {
- 0x000024,
- 0x023201,
- 0x000081,
- 0x000400,
- 0x00104c,
- 0x001101,
- 0x001200,
- 0x001300,
- 0x001414,
- 0x001500,
- 0x001604,
- 0x001704,
- 0x001807,
- 0x001900,
- //0x001a00,//for debug
- 0x001a32,
- 0x001b12,
- 0x001c44,
- 0x001d00,
- 0x001e00,
- 0x00f062,
- 0x00f162,
- 0x00f262,
- 0x00f362,
- 0x00f462,
- 0x00f562,
- 0x00f662,
- 0x00f762,
- 0x00f862,
- 0x00f962,
- 0x00fa62,
- 0x00fb62,
- 0x00fc00,
- 0x00fd00,
- 0x019021,
- 0x019100,
- 0x019200,
- 0x019321,
- 0x019400,
- 0x019500,
- 0x019611,
- 0x019700,
- 0x019800,
- 0x019900,
- 0x019a00,
- 0x019b00,
- 0x01e003,
- 0x01e102,
- 0x023000,
- 0x023201,
- 0x0b0201,
- 0x0b0300,
- 0x001fff,
- 0x0a0000,
- 0x0a0100,
- 0x0a0200,
- 0x0a0302,
- 0x0a0400,
- 0x0a0504,
- 0x0a060e,
- 0x0a0700,
- 0x0a0810,
- 0x0a090e,
- 0x0a0a00,
- 0x0a0bf0,
- 0x0a0c0b,
- 0x0a0d01,
- 0x0a0e90,
- 0x0a0f01,
- 0x0a1001,
- 0x0a11e0,
- 0x0a1201,
- 0x0a1302,
- 0x0a1430,
- 0x0a1580,
- 0x0a16ff,
- 0x023201,
- 0x0b0301,
- 0x023201,
-};
-
-
-const unsigned int CLKGEN_SELECT = 145;
-
-
-enum gpio_direction {IN, OUT};
-
-class gpio {
- public:
-
- gpio(unsigned int gpio_num, gpio_direction pin_direction, bool close_action);
- ~gpio();
-
- bool get_value();
- void set_value(bool state);
-
- private:
-
- unsigned int gpio_num;
-
- std::stringstream base_path;
- std::fstream value_file;
- std::fstream direction_file;
- bool close_action; // True set to input and release, false do nothing
-};
-
-class spidev {
- public:
-
- spidev(std::string dev_name);
- ~spidev();
-
- void send(char *wbuf, char *rbuf, unsigned int nbytes);
-
- private:
-
- int fd;
-
-};
-
-gpio::gpio(unsigned int _gpio_num, gpio_direction pin_direction, bool close_action)
-:close_action(close_action)
-{
- std::fstream export_file;
-
- gpio_num = _gpio_num;
-
- export_file.open("/sys/class/gpio/export", std::ios::out);
- if (!export_file.is_open()) ///\todo Poor error handling
- std::cout << "Failed to open gpio export file." << std::endl;
-
- export_file << gpio_num << std::endl;
-
- base_path << "/sys/class/gpio/gpio" << gpio_num << std::flush;
-
- std::string direction_file_name;
-
- direction_file_name = base_path.str() + "/direction";
-
- direction_file.open(direction_file_name.c_str());
- if (!direction_file.is_open())
- std::cout << "Failed to open direction file." << std::endl;
- if (pin_direction == OUT)
- direction_file << "out" << std::endl;
- else
- direction_file << "in" << std::endl;
-
- std::string value_file_name;
-
- value_file_name = base_path.str() + "/value";
-
- value_file.open(value_file_name.c_str(), std::ios_base::in | std::ios_base::out);
- if (!value_file.is_open())
- std::cout << "Failed to open value file." << std::endl;
-}
-
-bool gpio::get_value()
-{
-
- std::string val;
-
- std::getline(value_file, val);
- value_file.seekg(0);
-
- if (val == "0")
- return false;
- else if (val == "1")
- return true;
- else
- std::cout << "Data read from value file|" << val << "|" << std::endl;
-
- return false;
-}
-
-void gpio::set_value(bool state)
-{
-
- if (state)
- value_file << "1" << std::endl;
- else
- value_file << "0" << std::endl;
-}
-
-gpio::~gpio()
-{
- if (close_action) {
- std::fstream unexport_file;
-
- direction_file << "in" << std::endl;
-
- unexport_file.open("/sys/class/gpio/unexport", std::ios::out);
- if (!unexport_file.is_open()) ///\todo Poor error handling
- std::cout << "Failed to open gpio export file." << std::endl;
-
- unexport_file << gpio_num << std::endl;
-
- }
-
-}
-
-spidev::spidev(std::string fname)
-{
- int ret;
- int mode = 0;
- int speed = 12000;
- int bits = 24;
-
- fd = open(fname.c_str(), O_RDWR);
-
- ret = ioctl(fd, SPI_IOC_WR_MODE, &mode);
- ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed);
- ret = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits);
-}
-
-
-spidev::~spidev()
-{
- close(fd);
-}
-
-void spidev::send(char *buf, char *rbuf, unsigned int nbytes)
-{
- int ret;
-
- struct spi_ioc_transfer tr;
- tr.tx_buf = (unsigned long) buf;
- tr.rx_buf = (unsigned long) rbuf;
- tr.len = nbytes;
- tr.delay_usecs = 0;
- tr.speed_hz = 12000;
- tr.bits_per_word = 24;
-
- ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
-
-}
-
-static void send_config_to_clkgen(gpio &chip_select, const unsigned int data[], unsigned int data_size)
-{
- spidev spi("/dev/spidev1.0");
- unsigned int rbuf;
-
- for (unsigned int i = 0; i < data_size; i++) {
-
- //std::cout << "sending " << std::hex << data[i] << std::endl;
- chip_select.set_value(0);
- spi.send((char *)&data[i], (char *)&rbuf, 4);
- chip_select.set_value(1);
- unsigned int addr = (data[i] >> 8) & 0xfff;
- if (addr == 0x232 || addr == 0x000){
- std::cout << "." << std::flush;
- sleep(1);
- }
- };
- std::cout << std::endl;
-}
-
-}//namespace usrp_e_clkgen_config_utility
-
-//int main(int argc, char *argv[])
-static void clock_genconfig_main(void)
-{
- using namespace usrp_e_clkgen_config_utility;
- gpio clkgen_select(CLKGEN_SELECT, OUT, true);
-
- send_config_to_clkgen(clkgen_select, config_data, sizeof(config_data)/sizeof(config_data[0]));
-}
-
-#endif /*USRP_E_UTILS_CLKGEN_CONFIG_HPP*/
diff --git a/host/usrp_e_utils/usrp-e-debug-pins.c b/host/usrp_e_utils/usrp-e-debug-pins.c
index 94f898b67..570ae63d8 100644
--- a/host/usrp_e_utils/usrp-e-debug-pins.c
+++ b/host/usrp_e_utils/usrp-e-debug-pins.c
@@ -7,7 +7,7 @@
#include <sys/ioctl.h>
#include <linux/usrp_e.h>
-#include "usrp_e100_regs.hpp"
+#include "e100_regs.hpp"
// Usage: usrp_e_gpio <string>
@@ -54,24 +54,24 @@ int main(int argc, char *argv[])
if (strcmp(argv[1], "0") == 0) {
printf("Selected 0 based on %s\n", argv[1]);
- write_reg(UE_REG_GPIO_TX_DDR, 0xFFFF);
- write_reg(UE_REG_GPIO_RX_DDR, 0xFFFF);
- write_reg(UE_REG_GPIO_TX_SEL, 0x0);
- write_reg(UE_REG_GPIO_RX_SEL, 0x0);
- write_reg(UE_REG_GPIO_TX_DBG, 0xFFFF);
- write_reg(UE_REG_GPIO_RX_DBG, 0xFFFF);
+ write_reg(E100_REG_GPIO_TX_DDR, 0xFFFF);
+ write_reg(E100_REG_GPIO_RX_DDR, 0xFFFF);
+ write_reg(E100_REG_GPIO_TX_SEL, 0x0);
+ write_reg(E100_REG_GPIO_RX_SEL, 0x0);
+ write_reg(E100_REG_GPIO_TX_DBG, 0xFFFF);
+ write_reg(E100_REG_GPIO_RX_DBG, 0xFFFF);
} else if (strcmp(argv[1], "1") == 0) {
printf("Selected 1 based on %s\n", argv[1]);
- write_reg(UE_REG_GPIO_TX_DDR, 0xFFFF);
- write_reg(UE_REG_GPIO_RX_DDR, 0xFFFF);
- write_reg(UE_REG_GPIO_TX_SEL, 0xFFFF);
- write_reg(UE_REG_GPIO_RX_SEL, 0xFFFF);
- write_reg(UE_REG_GPIO_TX_DBG, 0xFFFF);
- write_reg(UE_REG_GPIO_RX_DBG, 0xFFFF);
+ write_reg(E100_REG_GPIO_TX_DDR, 0xFFFF);
+ write_reg(E100_REG_GPIO_RX_DDR, 0xFFFF);
+ write_reg(E100_REG_GPIO_TX_SEL, 0xFFFF);
+ write_reg(E100_REG_GPIO_RX_SEL, 0xFFFF);
+ write_reg(E100_REG_GPIO_TX_DBG, 0xFFFF);
+ write_reg(E100_REG_GPIO_RX_DBG, 0xFFFF);
} else {
printf("Selected off based on %s\n", argv[1]);
- write_reg(UE_REG_GPIO_TX_DDR, 0x0);
- write_reg(UE_REG_GPIO_RX_DDR, 0x0);
+ write_reg(E100_REG_GPIO_TX_DDR, 0x0);
+ write_reg(E100_REG_GPIO_RX_DDR, 0x0);
}
return 0;
diff --git a/host/usrp_e_utils/usrp-e-gpio.c b/host/usrp_e_utils/usrp-e-gpio.c
index 7e4bc4e13..4b788e945 100644
--- a/host/usrp_e_utils/usrp-e-gpio.c
+++ b/host/usrp_e_utils/usrp-e-gpio.c
@@ -7,7 +7,7 @@
#include <sys/ioctl.h>
#include "linux/usrp_e.h"
-#include "usrp_e100_regs.hpp"
+#include "e100_regs.hpp"
// Usage: usrp_e_gpio <string>
@@ -46,38 +46,38 @@ int main(int argc, char *argv[])
fp = open("/dev/usrp_e0", O_RDWR);
printf("fp = %d\n", fp);
- write_reg(UE_REG_GPIO_TX_DDR, 0x0);
- write_reg(UE_REG_GPIO_RX_DDR, 0xFFFF);
+ write_reg(E100_REG_GPIO_TX_DDR, 0x0);
+ write_reg(E100_REG_GPIO_RX_DDR, 0xFFFF);
for (i=0; i < 16; i++) {
- write_reg(UE_REG_GPIO_RX_IO, 1 << i);
+ write_reg(E100_REG_GPIO_RX_IO, 1 << i);
sleep(1);
if (test) {
- data_in = read_reg(UE_REG_GPIO_TX_IO);
+ data_in = read_reg(E100_REG_GPIO_TX_IO);
if (data_in != (1 << i))
printf("Read failed, wrote: %X read: %X\n", \
1 << i, data_in);
}
}
- write_reg(UE_REG_GPIO_RX_DDR, 0x0);
- write_reg(UE_REG_GPIO_TX_DDR, 0xFFFF);
+ write_reg(E100_REG_GPIO_RX_DDR, 0x0);
+ write_reg(E100_REG_GPIO_TX_DDR, 0xFFFF);
sleep(1);
for (i=0; i < 16; i++) {
- write_reg(UE_REG_GPIO_TX_IO, 1 << i);
+ write_reg(E100_REG_GPIO_TX_IO, 1 << i);
sleep(1);
if (test) {
- data_in = read_reg(UE_REG_GPIO_RX_IO);
+ data_in = read_reg(E100_REG_GPIO_RX_IO);
if (data_in != (1 << i))
printf("Read failed, wrote: %X read: %X\n", \
1 << i, data_in);
}
}
- write_reg(UE_REG_GPIO_RX_DDR, 0x0);
- write_reg(UE_REG_GPIO_TX_DDR, 0x0);
+ write_reg(E100_REG_GPIO_RX_DDR, 0x0);
+ write_reg(E100_REG_GPIO_TX_DDR, 0x0);
return 0;
}
diff --git a/host/usrp_e_utils/usrp-e-i2c.c b/host/usrp_e_utils/usrp-e-i2c.c
deleted file mode 100644
index c6fd4c632..000000000
--- a/host/usrp_e_utils/usrp-e-i2c.c
+++ /dev/null
@@ -1,87 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <fcntl.h>
-#include <sys/ioctl.h>
-
-#include <linux/usrp_e.h>
-
-// Usage: usrp_e_i2c w address data0 data1 data 2 ....
-// Usage: usrp_e_i2c r address count
-
-int main(int argc, char *argv[])
-{
- int fp, ret, i, tmp;
- struct usrp_e_i2c *i2c_msg;
- int direction, address, count;
-
- if (argc < 3) {
- printf("Usage: usrp-e-i2c w address data0 data1 data2 ...\n");
- printf("Usage: usrp-e-i2c r address count\n");
- printf("All addresses and data in hex.\n");
- exit(-1);
- }
-
- if (strcmp(argv[1], "r") == 0) {
- direction = 0;
- } else if (strcmp(argv[1], "w") == 0) {
- direction = 1;
- } else {
- return -1;
- }
-
- sscanf(argv[2], "%X", &address);
- printf("Address = %X\n", address);
-
- fp = open("/dev/usrp_e0", O_RDWR);
- printf("fp = %d\n", fp);
- if (fp < 0) {
- perror("Open failed");
- return -1;
- }
-
-// sleep(1);
-
- if (direction) {
- count = argc - 3;
- } else {
- sscanf(argv[3], "%X", &count);
- }
- printf("Count = %X\n", count);
-
- i2c_msg = malloc(sizeof(i2c_msg) + count * sizeof(char));
-
- i2c_msg->addr = address;
- i2c_msg->len = count;
-
- for (i = 0; i < count; i++) {
- i2c_msg->data[i] = i;
- }
-
- if (direction) {
- // Write
-
- for (i=0; i<count; i++) {
- sscanf(argv[3+i], "%X", &tmp);
- i2c_msg->data[i] = tmp;
- }
-
- ret = ioctl(fp, USRP_E_I2C_WRITE, i2c_msg);
- printf("Return value from i2c_write ioctl: %d\n", ret);
- } else {
- // Read
-
- ret = ioctl(fp, USRP_E_I2C_READ, i2c_msg);
- printf("Return value from i2c_read ioctl: %d\n", ret);
-
- printf("Ioctl: %d Data read :", ret);
- for (i=0; i<count; i++) {
- printf(" %X", i2c_msg->data[i]);
- }
- printf("\n");
-
- }
- return 0;
-}
diff --git a/host/usrp_e_utils/usrp-e-spi.c b/host/usrp_e_utils/usrp-e-spi.c
deleted file mode 100644
index 5203f56a8..000000000
--- a/host/usrp_e_utils/usrp-e-spi.c
+++ /dev/null
@@ -1,54 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <fcntl.h>
-#include <sys/ioctl.h>
-
-#include <linux/usrp_e.h>
-
-// Usage: usrp_e_spi w|rb slave data
-
-int main(int argc, char *argv[])
-{
- int fp, slave, length, ret;
- unsigned int data;
- struct usrp_e_spi spi_dat;
-
- if (argc < 5) {
- printf("Usage: usrp_e_spi w|rb slave transfer_length data\n");
- exit(-1);
- }
-
- slave = atoi(argv[2]);
- length = atoi(argv[3]);
- data = atoll(argv[4]);
-
- printf("Data = %X\n", data);
-
- fp = open("/dev/usrp_e0", O_RDWR);
- printf("fp = %d\n", fp);
- if (fp < 0) {
- perror("Open failed");
- return -1;
- }
-
-// sleep(1);
-
-
- spi_dat.slave = slave;
- spi_dat.data = data;
- spi_dat.length = length;
- spi_dat.flags = UE_SPI_PUSH_FALL | UE_SPI_LATCH_RISE;
-
- if (*argv[1] == 'r') {
- spi_dat.readback = 1;
- ret = ioctl(fp, USRP_E_SPI, &spi_dat);
- printf("Ioctl returns: %d, Data returned = %d\n", ret, spi_dat.data);
- } else {
- spi_dat.readback = 0;
- ioctl(fp, USRP_E_SPI, &spi_dat);
- }
-
- return 0;
-}
diff --git a/host/usrp_e_utils/usrp-e-utility.cpp b/host/usrp_e_utils/usrp-e-utility.cpp
deleted file mode 100644
index 47a2c0900..000000000
--- a/host/usrp_e_utils/usrp-e-utility.cpp
+++ /dev/null
@@ -1,72 +0,0 @@
-//
-// Copyright 2011 Ettus Research LLC
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// 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/safe_main.hpp>
-#include <boost/program_options.hpp>
-#include <boost/format.hpp>
-#include <stdexcept>
-#include <iostream>
-
-#include "fpga_downloader.cpp"
-#include "clkgen_config.hpp"
-
-namespace po = boost::program_options;
-
-int UHD_SAFE_MAIN(int argc, char *argv[]){
-
- //variables to be set by po
- std::string fpga_path;
-
- //setup the program options
- po::options_description desc("Allowed options");
- desc.add_options()
- ("help", "help message")
- ("fpga", po::value<std::string>(&fpga_path), "loads the specified FPGA file")
- ("reclk", "runs the clock recovery")
- ;
- 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 USRP-E Utility %s") % desc << std::endl;
- return ~0;
- }
-
- bool loaded_fpga_image = false;
- if (vm.count("fpga") != 0){
- std::cout << "USRP-E Utility loading the FPGA..." << std::endl << std::endl;
- usrp_e100_load_fpga(fpga_path);
- loaded_fpga_image = true;
- sleep(1);
- }
-
- if (vm.count("reclk") != 0){
- std::cout << "USRP-E Utility running the clock recovery..." << std::flush;
- //if an image was not loaded or specified, we load pass-through
- if (fpga_path.empty()) throw std::runtime_error(
- "Please specify the path to the pass-though FPGA image for your device.\n"
- " usrp-e-utility --reclk --fpga=/usr/share/uhd/images/usrp_e1xx_pt_fpga.bin"
- );
- clock_genconfig_main();
- }
-
- std::cout << "Done!" << std::endl;
-
- return 0;
-}
diff --git a/host/usrp_e_utils/usrp-e-wb-test.cpp b/host/usrp_e_utils/usrp-e-wb-test.cpp
index 3d6a8d101..eab4caede 100644
--- a/host/usrp_e_utils/usrp-e-wb-test.cpp
+++ b/host/usrp_e_utils/usrp-e-wb-test.cpp
@@ -24,7 +24,7 @@
#include <fcntl.h> //open, close
#include <linux/usrp_e.h>
-#include "usrp_e100_regs.hpp"
+#include "e100_regs.hpp"
static const size_t num_test_iters = 10000000;
@@ -88,21 +88,21 @@ int main(int, char *[]){
//make random values
int random_test32 = ::random();
int random_test16 = ::random() & 0xffff;
- int random_secs = ::random();
+ //int random_secs = ::random();
//set a bunch of registers
- poke16(UE_REG_MISC_TEST, random_test16);
- poke32(UE_REG_SR_MISC_TEST32, random_test32);
- poke32(UE_REG_TIME64_TICKS, 0);
- poke32(UE_REG_TIME64_IMM, 1); //immediate
- poke32(UE_REG_TIME64_SECS, random_secs);
+ poke16(E100_REG_MISC_TEST, random_test16);
+ poke32(E100_REG_SR_MISC_TEST32, random_test32);
+ //poke32(E100_REG_TIME64_TICKS, 0);
+ //poke32(E100_REG_TIME64_IMM, 1); //immediate
+ //poke32(E100_REG_TIME64_SECS, random_secs);
//read a bunch of registers
if (
- (peek16(UE_REG_MISC_TEST) == random_test16) and
- (peek32(UE_REG_RB_MISC_TEST32) == random_test32) and
- (peek32(UE_REG_RB_TIME_NOW_SECS) == random_secs) and
-// (peek32(UE_REG_RB_TIME_NOW_TICKS) < 1000000) and
+ (peek16(E100_REG_MISC_TEST) == random_test16) and
+ (peek32(E100_REG_RB_MISC_TEST32) == random_test32) and
+// (peek32(E100_REG_RB_TIME_NOW_SECS) == random_secs) and
+// (peek32(E100_REG_RB_TIME_NOW_TICKS) < 1000000) and
true) num_pass++;
else num_fail++;
}
diff --git a/host/utils/uhd_usrp_probe.cpp b/host/utils/uhd_usrp_probe.cpp
index 3ea63c4bb..cb6d78255 100644
--- a/host/utils/uhd_usrp_probe.cpp
+++ b/host/utils/uhd_usrp_probe.cpp
@@ -18,13 +18,8 @@
#include <uhd/utils/safe_main.hpp>
#include <uhd/device.hpp>
#include <uhd/types/ranges.hpp>
+#include <uhd/property_tree.hpp>
#include <boost/algorithm/string.hpp> //for split
-#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>
#include <uhd/usrp/mboard_eeprom.hpp>
#include <uhd/usrp/dboard_eeprom.hpp>
@@ -56,17 +51,16 @@ static std::string make_border(const std::string &text){
return ss.str();
}
-static std::string get_dsp_pp_string(const std::string &type, wax::obj dsp){
+static std::string get_dsp_pp_string(const std::string &type, property_tree::sptr tree, const property_tree::path_type &path){
std::stringstream ss;
- ss << boost::format("%s DSP: %s") % type % dsp[usrp::DSP_PROP_NAME].as<std::string>() << std::endl;
+ ss << boost::format("%s DSP: %s") % type % path.leaf() << std::endl;
//ss << std::endl;
- ss << boost::format("Codec Rate: %f Msps") % (dsp[usrp::DSP_PROP_CODEC_RATE].as<double>()/1e6) << std::endl;
- //ss << boost::format("Host Rate: %f Msps") % (dsp[usrp::DSP_PROP_HOST_RATE].as<double>()/1e6) << std::endl;
- //ss << boost::format("Freq Shift: %f Mhz") % (dsp[usrp::DSP_PROP_FREQ_SHIFT].as<double>()/1e6) << std::endl;
+ meta_range_t freq_range = tree->access<meta_range_t>(path / "freq/range").get();
+ ss << boost::format("Freq range: %.3f to %.3f Mhz") % (freq_range.start()/1e6) % (freq_range.stop()/1e6) << std::endl;;
return ss.str();
}
-static std::string prop_names_to_pp_string(const prop_names_t &prop_names){
+static std::string prop_names_to_pp_string(const std::vector<std::string> &prop_names){
std::stringstream ss; size_t count = 0;
BOOST_FOREACH(const std::string &prop_name, prop_names){
ss << ((count++)? ", " : "") << prop_name;
@@ -74,101 +68,117 @@ static std::string prop_names_to_pp_string(const prop_names_t &prop_names){
return ss.str();
}
-static std::string get_subdev_pp_string(const std::string &type, wax::obj subdev){
+static std::string get_subdev_pp_string(const std::string &type, property_tree::sptr tree, const property_tree::path_type &path){
std::stringstream ss;
- ss << boost::format("%s Subdev: %s") % type % subdev[usrp::SUBDEV_PROP_NAME].as<std::string>() << std::endl;
+ ss << boost::format("%s Subdev: %s") % type % path.leaf() << std::endl;
//ss << std::endl;
- prop_names_t ant_names(subdev[usrp::SUBDEV_PROP_ANTENNA_NAMES].as<prop_names_t>());
- ss << boost::format("Antennas: %s") % prop_names_to_pp_string(ant_names) << std::endl;
+ ss << boost::format("Name: %s") % (tree->access<std::string>(path / "name").get()) << std::endl;
+ ss << boost::format("Antennas: %s") % prop_names_to_pp_string(tree->access<std::vector<std::string> >(path / "antenna/options").get()) << std::endl;
+ ss << boost::format("Sensors: %s") % prop_names_to_pp_string(tree->list(path / "sensors")) << std::endl;
- freq_range_t freq_range(subdev[usrp::SUBDEV_PROP_FREQ_RANGE].as<freq_range_t>());
+ meta_range_t freq_range = tree->access<meta_range_t>(path / "freq/range").get();
ss << boost::format("Freq range: %.3f to %.3f Mhz") % (freq_range.start()/1e6) % (freq_range.stop()/1e6) << std::endl;
- prop_names_t gain_names(subdev[usrp::SUBDEV_PROP_GAIN_NAMES].as<prop_names_t>());
+ std::vector<std::string> gain_names = tree->list(path / "gains");
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(subdev[named_prop_t(usrp::SUBDEV_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.start() % gain_range.stop() % gain_range.step() << std::endl;
+ BOOST_FOREACH(const std::string &name, gain_names){
+ meta_range_t gain_range = tree->access<meta_range_t>(path / "gains" / name / "range").get();
+ ss << boost::format("Gain range %s: %.1f to %.1f step %.1f dB") % name % gain_range.start() % gain_range.stop() % gain_range.step() << 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;
+ ss << boost::format("Connection Type: %s") % (tree->access<std::string>(path / "connection").get()) << std::endl;
+ ss << boost::format("Uses LO offset: %s") % ((tree->access<bool>(path / "use_lo_offset").get())? "Yes" : "No") << std::endl;
return ss.str();
}
-static std::string get_codec_pp_string(const std::string &type, wax::obj codec){
+static std::string get_codec_pp_string(const std::string &type, property_tree::sptr tree, const property_tree::path_type &path){
std::stringstream ss;
- ss << boost::format("%s Codec: %s") % type % codec[usrp::CODEC_PROP_NAME].as<std::string>() << std::endl;
+ ss << boost::format("%s Codec: %s") % type % path.leaf() << std::endl;
//ss << std::endl;
- prop_names_t gain_names(codec[usrp::CODEC_PROP_GAIN_NAMES].as<prop_names_t>());
+
+ ss << boost::format("Name: %s") % (tree->access<std::string>(path / "name").get()) << std::endl;
+ std::vector<std::string> gain_names = tree->list(path / "gains");
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.start() % gain_range.stop() % gain_range.step() << std::endl;
+ BOOST_FOREACH(const std::string &name, gain_names){
+ meta_range_t gain_range = tree->access<meta_range_t>(path / "gains" / name / "range").get();
+ ss << boost::format("Gain range %s: %.1f to %.1f step %.1f dB") % name % gain_range.start() % gain_range.stop() % gain_range.step() << std::endl;
}
return ss.str();
}
-static std::string get_dboard_pp_string(const std::string &type, wax::obj dboard){
+static std::string get_dboard_pp_string(const std::string &type, property_tree::sptr tree, const property_tree::path_type &path){
std::stringstream ss;
- ss << boost::format("%s Dboard: %s") % type % dboard[usrp::DBOARD_PROP_NAME].as<std::string>() << std::endl;
+ ss << boost::format("%s Dboard: %s") % type % path.leaf() << std::endl;
//ss << std::endl;
- usrp::dboard_eeprom_t db_eeprom = dboard[usrp::DBOARD_PROP_DBOARD_EEPROM].as<usrp::dboard_eeprom_t>();
+ const std::string prefix = (type == "RX")? "rx" : "tx";
+ usrp::dboard_eeprom_t db_eeprom = tree->access<usrp::dboard_eeprom_t>(path / (prefix + "_eeprom")).get();
if (db_eeprom.id != usrp::dboard_id_t::none()) ss << boost::format("ID: %s") % db_eeprom.id.to_pp_string() << std::endl;
if (not db_eeprom.serial.empty()) ss << boost::format("Serial: %s") % db_eeprom.serial << std::endl;
if (type == "TX"){
- usrp::dboard_eeprom_t gdb_eeprom = dboard[usrp::DBOARD_PROP_GBOARD_EEPROM].as<usrp::dboard_eeprom_t>();
- if (gdb_eeprom.id != usrp::dboard_id_t::none()) ss << boost::format("GDB ID: %s") % gdb_eeprom.id.to_pp_string() << std::endl;
- if (not gdb_eeprom.serial.empty()) ss << boost::format("GDB Serial: %s") % gdb_eeprom.serial << std::endl;
+ usrp::dboard_eeprom_t gdb_eeprom = tree->access<usrp::dboard_eeprom_t>(path / "gdb_eeprom").get();
+ if (gdb_eeprom.id != usrp::dboard_id_t::none()) ss << boost::format("ID: %s") % gdb_eeprom.id.to_pp_string() << std::endl;
+ if (not gdb_eeprom.serial.empty()) ss << boost::format("Serial: %s") % gdb_eeprom.serial << std::endl;
}
- 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)]));
+ BOOST_FOREACH(const std::string &name, tree->list(path / (prefix + "_frontends"))){
+ ss << make_border(get_subdev_pp_string(type, tree, path / (prefix + "_frontends") / name));
}
- ss << make_border(get_codec_pp_string(type, dboard[usrp::DBOARD_PROP_CODEC]));
+ ss << make_border(get_codec_pp_string(type, tree, path.branch_path().branch_path() / (prefix + "_codecs") / path.leaf()));
return ss.str();
}
-static std::string get_mboard_pp_string(wax::obj mboard){
+static std::string get_mboard_pp_string(property_tree::sptr tree, const property_tree::path_type &path){
std::stringstream ss;
- ss << boost::format("Mboard: %s") % mboard[usrp::MBOARD_PROP_NAME].as<std::string>() << std::endl;
+ ss << boost::format("Mboard: %s") % (tree->access<std::string>(path / "name").get()) << std::endl;
//ss << std::endl;
- usrp::mboard_eeprom_t mb_eeprom = mboard[usrp::MBOARD_PROP_EEPROM_MAP].as<usrp::mboard_eeprom_t>();
+ usrp::mboard_eeprom_t mb_eeprom = tree->access<usrp::mboard_eeprom_t>(path / "eeprom").get();
BOOST_FOREACH(const std::string &key, mb_eeprom.keys()){
if (not mb_eeprom[key].empty()) ss << boost::format("%s: %s") % key % mb_eeprom[key] << std::endl;
}
- BOOST_FOREACH(const std::string &dsp_name, mboard[usrp::MBOARD_PROP_RX_DSP_NAMES].as<prop_names_t>()){
- ss << make_border(get_dsp_pp_string("RX", mboard[named_prop_t(usrp::MBOARD_PROP_RX_DSP, dsp_name)]));
+ ss << std::endl;
+ ss << "Time sources: " << prop_names_to_pp_string(tree->access<std::vector<std::string> >(path / "time_source" / "options").get()) << std::endl;
+ ss << "Clock sources: " << prop_names_to_pp_string(tree->access<std::vector<std::string> >(path / "clock_source" / "options").get()) << std::endl;
+ ss << "Sensors: " << prop_names_to_pp_string(tree->list(path / "sensors")) << std::endl;
+ BOOST_FOREACH(const std::string &name, tree->list(path / "rx_dsps")){
+ ss << make_border(get_dsp_pp_string("RX", tree, path / "rx_dsps" / name));
}
- BOOST_FOREACH(const std::string &db_name, mboard[usrp::MBOARD_PROP_RX_DBOARD_NAMES].as<prop_names_t>()){
- ss << make_border(get_dboard_pp_string("RX", mboard[named_prop_t(usrp::MBOARD_PROP_RX_DBOARD, db_name)]));
+ BOOST_FOREACH(const std::string &name, tree->list(path / "dboards")){
+ ss << make_border(get_dboard_pp_string("RX", tree, path / "dboards" / name));
}
- BOOST_FOREACH(const std::string &dsp_name, mboard[usrp::MBOARD_PROP_TX_DSP_NAMES].as<prop_names_t>()){
- ss << make_border(get_dsp_pp_string("TX", mboard[named_prop_t(usrp::MBOARD_PROP_TX_DSP, dsp_name)]));
+ BOOST_FOREACH(const std::string &name, tree->list(path / "tx_dsps")){
+ ss << make_border(get_dsp_pp_string("TX", tree, path / "tx_dsps" / name));
}
- BOOST_FOREACH(const std::string &db_name, mboard[usrp::MBOARD_PROP_TX_DBOARD_NAMES].as<prop_names_t>()){
- ss << make_border(get_dboard_pp_string("TX", mboard[named_prop_t(usrp::MBOARD_PROP_TX_DBOARD, db_name)]));
+ BOOST_FOREACH(const std::string &name, tree->list(path / "dboards")){
+ ss << make_border(get_dboard_pp_string("TX", tree, path / "dboards" / name));
}
return ss.str();
}
-static std::string get_device_pp_string(device::sptr dev){
+static std::string get_device_pp_string(property_tree::sptr tree){
std::stringstream ss;
- ss << boost::format("Device: %s") % (*dev)[usrp::DEVICE_PROP_NAME].as<std::string>() << std::endl;
+ ss << boost::format("Device: %s") % (tree->access<std::string>("/name").get()) << std::endl;
//ss << std::endl;
- BOOST_FOREACH(const std::string &mboard_name, (*dev)[usrp::DEVICE_PROP_MBOARD_NAMES].as<prop_names_t>()){
- ss << make_border(get_mboard_pp_string((*dev)[named_prop_t(usrp::DEVICE_PROP_MBOARD, mboard_name)]));
+ BOOST_FOREACH(const std::string &name, tree->list("/mboards")){
+ ss << make_border(get_mboard_pp_string(tree, "/mboards/" + name));
}
return ss.str();
}
+void print_tree(const uhd::property_tree::path_type &path, uhd::property_tree::sptr tree){
+ std::cout << path << std::endl;
+ BOOST_FOREACH(const std::string &name, tree->list(path)){
+ print_tree(path / name, tree);
+ }
+}
+
int UHD_SAFE_MAIN(int argc, char *argv[]){
po::options_description desc("Allowed options");
desc.add_options()
("help", "help message")
("args", po::value<std::string>()->default_value(""), "device address args")
+ ("tree", "specify to print a complete property tree")
;
po::variables_map vm;
@@ -182,8 +192,10 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
}
device::sptr dev = device::make(vm["args"].as<std::string>());
+ property_tree::sptr tree = (*dev)[0].as<property_tree::sptr>();
- std::cout << make_border(get_device_pp_string(dev)) << std::endl;
+ if (vm.count("tree") != 0) print_tree("/", tree);
+ else std::cout << make_border(get_device_pp_string(tree)) << std::endl;
return 0;
}
diff --git a/host/utils/usrp1_init_eeprom.cpp b/host/utils/usrp1_init_eeprom.cpp
index 39f091af4..5bc07daf6 100644
--- a/host/utils/usrp1_init_eeprom.cpp
+++ b/host/utils/usrp1_init_eeprom.cpp
@@ -17,7 +17,7 @@
#include <uhd/utils/safe_main.hpp>
#include <uhd/device.hpp>
-#include <uhd/usrp/device_props.hpp>
+#include <uhd/property_tree.hpp>
#include <boost/program_options.hpp>
#include <boost/format.hpp>
#include <iostream>
@@ -65,8 +65,8 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
std::cout << "Writing EEPROM data..." << std::endl;
//uhd::device_addrs_t devs = uhd::device::find(found_addrs[i]);
uhd::device::sptr dev = uhd::device::make(found_addrs[i]);
- wax::obj mb = (*dev)[uhd::usrp::DEVICE_PROP_MBOARD];
- mb[std::string("load_eeprom")] = vm["image"].as<std::string>();
+ uhd::property_tree::sptr tree = (*dev)[0].as<uhd::property_tree::sptr>();
+ tree->access<std::string>("/mboards/0/load_eeprom").set(vm["image"].as<std::string>());
}
diff --git a/host/utils/usrp_burn_db_eeprom.cpp b/host/utils/usrp_burn_db_eeprom.cpp
index 58417bd68..7ebbe7756 100644
--- a/host/utils/usrp_burn_db_eeprom.cpp
+++ b/host/utils/usrp_burn_db_eeprom.cpp
@@ -20,10 +20,9 @@
#include <uhd/device.hpp>
#include <uhd/types/dict.hpp>
#include <uhd/utils/assert_has.hpp>
+#include <uhd/property_tree.hpp>
#include <uhd/usrp/dboard_eeprom.hpp>
-#include <uhd/usrp/device_props.hpp>
-#include <uhd/usrp/mboard_props.hpp>
-#include <uhd/usrp/dboard_props.hpp>
+#include <boost/algorithm/string.hpp>
#include <boost/program_options.hpp>
#include <boost/format.hpp>
#include <boost/assign.hpp>
@@ -36,15 +35,6 @@ namespace po = boost::program_options;
int UHD_SAFE_MAIN(int argc, char *argv[]){
//command line variables
std::string args, slot, unit;
- static const uhd::dict<std::string, mboard_prop_t> unit_to_db_prop = boost::assign::map_list_of
- ("RX", MBOARD_PROP_RX_DBOARD) ("TX", MBOARD_PROP_TX_DBOARD) ("GDB", MBOARD_PROP_TX_DBOARD)
- ;
- static const uhd::dict<std::string, mboard_prop_t> unit_to_db_names_prop = boost::assign::map_list_of
- ("RX", MBOARD_PROP_RX_DBOARD_NAMES) ("TX", MBOARD_PROP_TX_DBOARD_NAMES) ("GDB", MBOARD_PROP_TX_DBOARD_NAMES)
- ;
- static const uhd::dict<std::string, dboard_prop_t> unit_to_db_eeprom_prop = boost::assign::map_list_of
- ("RX", DBOARD_PROP_DBOARD_EEPROM) ("TX", DBOARD_PROP_DBOARD_EEPROM) ("GDB", DBOARD_PROP_GBOARD_EEPROM)
- ;
po::options_description desc("Allowed options");
desc.add_options()
@@ -70,34 +60,30 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
return ~0;
}
- //check inputs
- if (not unit_to_db_prop.has_key(unit)){
- std::cout << "Error: specify RX or TX for unit" << std::endl;
- return ~0;
- }
-
//make the device and extract the dboard w/ property
device::sptr dev = device::make(args);
- uhd::prop_names_t dboard_names = (*dev)[DEVICE_PROP_MBOARD][unit_to_db_names_prop[unit]].as<uhd::prop_names_t>();
+ uhd::property_tree::sptr tree = (*dev)[0].as<uhd::property_tree::sptr>();
+ const uhd::property_tree::path_type db_root = "/mboards/0/dboards";
+ std::vector<std::string> dboard_names = tree->list(db_root);
if (dboard_names.size() == 1 and slot.empty()) slot = dboard_names.front();
uhd::assert_has(dboard_names, slot, "dboard slot name");
- wax::obj dboard = (*dev)[DEVICE_PROP_MBOARD][named_prop_t(unit_to_db_prop[unit], slot)];
- std::string prefix = unit + ":" + slot;
- std::cout << boost::format("Reading EEPROM on %s dboard...") % prefix << std::endl;
- dboard_eeprom_t db_eeprom = dboard[unit_to_db_eeprom_prop[unit]].as<dboard_eeprom_t>();
+ std::cout << boost::format("Reading %s EEPROM on %s dboard...") % unit % slot << std::endl;
+ boost::to_lower(unit);
+ const uhd::property_tree::path_type db_path = db_root / slot / (unit + "_eeprom");
+ dboard_eeprom_t db_eeprom = tree->access<dboard_eeprom_t>(db_path).get();
//------------- handle the dboard ID -----------------------------//
if (vm.count("id")){
db_eeprom.id = dboard_id_t::from_string(vm["id"].as<std::string>());
- dboard[unit_to_db_eeprom_prop[unit]] = db_eeprom;
+ tree->access<dboard_eeprom_t>(db_path).set(db_eeprom);
}
std::cout << boost::format(" Current ID: %s") % db_eeprom.id.to_pp_string() << std::endl;
//------------- handle the dboard serial--------------------------//
if (vm.count("ser")){
db_eeprom.serial = vm["ser"].as<std::string>();
- dboard[unit_to_db_eeprom_prop[unit]] = db_eeprom;
+ tree->access<dboard_eeprom_t>(db_path).set(db_eeprom);
}
std::cout << boost::format(" Current serial: \"%s\"") % db_eeprom.serial << std::endl;
diff --git a/host/utils/usrp_burn_mb_eeprom.cpp b/host/utils/usrp_burn_mb_eeprom.cpp
index 20e1b58b1..9f2fa611a 100644
--- a/host/utils/usrp_burn_mb_eeprom.cpp
+++ b/host/utils/usrp_burn_mb_eeprom.cpp
@@ -17,8 +17,7 @@
#include <uhd/utils/safe_main.hpp>
#include <uhd/device.hpp>
-#include <uhd/usrp/device_props.hpp>
-#include <uhd/usrp/mboard_props.hpp>
+#include <uhd/property_tree.hpp>
#include <uhd/usrp/mboard_eeprom.hpp>
#include <boost/program_options.hpp>
#include <boost/format.hpp>
@@ -53,14 +52,12 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
std::cout << "Creating USRP device from address: " + args << std::endl;
uhd::device::sptr dev = uhd::device::make(args);
- //FIXME the default mboard for now (may be others)
- wax::obj mboard = (*dev)[uhd::usrp::DEVICE_PROP_MBOARD];
+ uhd::property_tree::sptr tree = (*dev)[0].as<uhd::property_tree::sptr>();
std::cout << std::endl;
if (true /*always readback*/){
std::cout << "Fetching current settings from EEPROM..." << std::endl;
- uhd::usrp::mboard_eeprom_t mb_eeprom = \
- mboard[uhd::usrp::MBOARD_PROP_EEPROM_MAP].as<uhd::usrp::mboard_eeprom_t>();
+ uhd::usrp::mboard_eeprom_t mb_eeprom = tree->access<uhd::usrp::mboard_eeprom_t>("/mboards/0/eeprom").get();
if (not mb_eeprom.has_key(key)){
std::cerr << boost::format("Cannot find value for EEPROM[%s]") % key << std::endl;
return ~0;
@@ -71,7 +68,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
if (vm.count("val")){
uhd::usrp::mboard_eeprom_t mb_eeprom; mb_eeprom[key] = val;
std::cout << boost::format("Setting EEPROM [\"%s\"] to \"%s\"...") % key % val << std::endl;
- mboard[uhd::usrp::MBOARD_PROP_EEPROM_MAP] = mb_eeprom;
+ tree->access<uhd::usrp::mboard_eeprom_t>("/mboards/0/eeprom").set(mb_eeprom);
std::cout << "Power-cycle the USRP device for the changes to take effect." << std::endl;
std::cout << std::endl;
}
diff --git a/images/Makefile b/images/Makefile
index 10e3eb7ba..04d828b60 100644
--- a/images/Makefile
+++ b/images/Makefile
@@ -227,7 +227,7 @@ endif
ifdef HAS_XTCLSH
_usrp_e100_fpga_dir = $(TOP_FPGA_DIR)/usrp2/top/E1x0
-_usrp_e100_fpga_bin = $(BUILT_IMAGES_DIR)/usrp_e100_fpga.bin
+_usrp_e100_fpga_bin = $(BUILT_IMAGES_DIR)/usrp_e100_fpga_v2.bin
IMAGES_LIST += $(_usrp_e100_fpga_bin)
$(_usrp_e100_fpga_bin): $(GLOBAL_DEPS)