aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--README.txt19
-rw-r--r--firmware/README6
-rw-r--r--firmware/README.txt31
-rw-r--r--firmware/fx2/b100/usrp_common.c57
-rw-r--r--firmware/fx2/b100/usrp_main.c153
-rw-r--r--firmware/fx2/b100/usrp_regs.h28
-rw-r--r--firmware/fx2/common/fx2regs.h17
-rwxr-xr-xfix-copyright-years71
-rw-r--r--fpga/README4
-rw-r--r--fpga/README.txt78
-rw-r--r--fpga/usrp2/control_lib/Makefile.srcs3
-rw-r--r--fpga/usrp2/control_lib/double_buffer_tb.v109
-rw-r--r--fpga/usrp2/control_lib/user_settings.v63
-rw-r--r--fpga/usrp2/custom/custom_dsp_rx.v71
-rw-r--r--fpga/usrp2/custom/custom_dsp_tx.v71
-rw-r--r--fpga/usrp2/custom/custom_engine_rx.v53
-rw-r--r--fpga/usrp2/custom/custom_engine_tx.v57
-rw-r--r--fpga/usrp2/custom/power_trig.v130
-rw-r--r--fpga/usrp2/custom/power_trig_tb.v71
-rw-r--r--fpga/usrp2/gpif/Makefile.srcs1
-rw-r--r--fpga/usrp2/gpif/packet_reframer.v34
-rw-r--r--fpga/usrp2/gpif/slave_fifo.v467
-rw-r--r--fpga/usrp2/sdr_lib/Makefile.srcs9
-rw-r--r--fpga/usrp2/sdr_lib/cordic_z24.v2
-rw-r--r--fpga/usrp2/sdr_lib/ddc_chain.v190
-rw-r--r--fpga/usrp2/sdr_lib/dsp_core_rx.v144
-rw-r--r--fpga/usrp2/sdr_lib/dsp_core_rx_old.v200
-rw-r--r--fpga/usrp2/sdr_lib/dsp_core_rx_tb.v10
-rw-r--r--fpga/usrp2/sdr_lib/dsp_core_rx_udp.v200
-rw-r--r--fpga/usrp2/sdr_lib/dsp_rx_glue.v98
-rw-r--r--fpga/usrp2/sdr_lib/dsp_tx_glue.v98
-rw-r--r--fpga/usrp2/sdr_lib/dspengine_16to8.v38
-rw-r--r--fpga/usrp2/sdr_lib/dspengine_8to16.v203
-rw-r--r--fpga/usrp2/sdr_lib/duc_chain.v (renamed from fpga/usrp2/sdr_lib/dsp_core_tx.v)74
-rw-r--r--fpga/usrp2/sdr_lib/dummy_rx.v2
-rw-r--r--fpga/usrp2/timing/time_64bit.v48
-rw-r--r--fpga/usrp2/timing/time_compare.v44
-rw-r--r--fpga/usrp2/top/B100/B100.ucf16
-rw-r--r--fpga/usrp2/top/B100/B100.v16
-rw-r--r--fpga/usrp2/top/B100/Makefile.B10016
-rwxr-xr-xfpga/usrp2/top/B100/core_compile2
-rw-r--r--fpga/usrp2/top/B100/timing.ucf9
-rw-r--r--fpga/usrp2/top/B100/u1plus_core.v122
-rw-r--r--fpga/usrp2/top/E1x0/Makefile.E10011
-rw-r--r--fpga/usrp2/top/E1x0/Makefile.E11011
-rwxr-xr-xfpga/usrp2/top/E1x0/core_compile2
-rw-r--r--fpga/usrp2/top/E1x0/u1e_core.v102
-rw-r--r--fpga/usrp2/top/N2x0/Makefile.N200R312
-rw-r--r--fpga/usrp2/top/N2x0/Makefile.N200R411
-rw-r--r--fpga/usrp2/top/N2x0/Makefile.N210R312
-rw-r--r--fpga/usrp2/top/N2x0/Makefile.N210R411
-rw-r--r--fpga/usrp2/top/N2x0/u2plus_core.v100
-rw-r--r--fpga/usrp2/top/USRP2/Makefile12
-rw-r--r--fpga/usrp2/top/USRP2/u2_core.v100
-rw-r--r--fpga/usrp2/vrt/Makefile.srcs2
-rw-r--r--fpga/usrp2/vrt/gen_context_pkt.v18
-rw-r--r--fpga/usrp2/vrt/vita_rx_chain.v31
-rw-r--r--fpga/usrp2/vrt/vita_rx_engine_glue.v95
-rw-r--r--fpga/usrp2/vrt/vita_rx_framer.v38
-rw-r--r--fpga/usrp2/vrt/vita_tx_chain.v103
-rw-r--r--fpga/usrp2/vrt/vita_tx_control.v17
-rw-r--r--fpga/usrp2/vrt/vita_tx_deframer.v99
-rw-r--r--fpga/usrp2/vrt/vita_tx_engine_glue.v99
-rw-r--r--host/examples/benchmark_rate.cpp15
-rw-r--r--host/examples/test_messages.cpp3
-rw-r--r--host/examples/tx_waveforms.cpp5
-rw-r--r--host/include/uhd/stream.hpp8
-rw-r--r--host/include/uhd/types/metadata.hpp15
-rw-r--r--host/include/uhd/types/time_spec.hpp28
-rw-r--r--host/include/uhd/usrp/multi_usrp.hpp10
-rw-r--r--host/lib/convert/CMakeLists.txt4
-rw-r--r--host/lib/convert/convert_common.hpp50
-rw-r--r--host/lib/convert/convert_fc32_to_sc8_with_sse2.cpp150
-rw-r--r--host/lib/convert/convert_fc32_with_sse2.cpp8
-rw-r--r--host/lib/convert/convert_fc64_to_sc8_with_sse2.cpp156
-rw-r--r--host/lib/convert/convert_fc64_with_sse2.cpp8
-rw-r--r--host/lib/convert/convert_orc.orc17
-rw-r--r--host/lib/convert/convert_with_orc.cpp11
-rw-r--r--host/lib/convert/convert_with_tables.cpp100
-rw-r--r--host/lib/convert/gen_convert_general.py18
-rw-r--r--[-rwxr-xr-x]host/lib/transport/gen_vrt_if_packet.py2
-rw-r--r--host/lib/transport/libusb1_zero_copy.cpp17
-rw-r--r--host/lib/transport/super_recv_packet_handler.hpp12
-rw-r--r--host/lib/transport/super_send_packet_handler.hpp14
-rw-r--r--host/lib/transport/usb_zero_copy_wrapper.cpp106
-rw-r--r--host/lib/types/time_spec.cpp58
-rw-r--r--host/lib/usrp/b100/b100_ctrl.cpp4
-rw-r--r--host/lib/usrp/b100/b100_impl.cpp48
-rw-r--r--host/lib/usrp/b100/b100_impl.hpp12
-rw-r--r--host/lib/usrp/b100/b100_regs.hpp36
-rw-r--r--host/lib/usrp/b100/io_impl.cpp61
-rw-r--r--host/lib/usrp/common/async_packet_handler.hpp71
-rw-r--r--host/lib/usrp/common/fx2_ctrl.cpp13
-rw-r--r--host/lib/usrp/common/fx2_ctrl.hpp6
-rw-r--r--host/lib/usrp/cores/CMakeLists.txt3
-rw-r--r--host/lib/usrp/cores/rx_dsp_core_200.cpp60
-rw-r--r--host/lib/usrp/cores/rx_dsp_core_200.hpp3
-rw-r--r--host/lib/usrp/cores/time64_core_200.cpp34
-rw-r--r--host/lib/usrp/cores/time64_core_200.hpp4
-rw-r--r--host/lib/usrp/cores/tx_dsp_core_200.cpp62
-rw-r--r--host/lib/usrp/cores/tx_dsp_core_200.hpp6
-rw-r--r--host/lib/usrp/cores/user_settings_core_200.cpp43
-rw-r--r--host/lib/usrp/cores/user_settings_core_200.hpp36
-rw-r--r--host/lib/usrp/e100/e100_impl.cpp17
-rw-r--r--host/lib/usrp/e100/e100_impl.hpp6
-rw-r--r--host/lib/usrp/e100/e100_regs.hpp32
-rw-r--r--host/lib/usrp/e100/io_impl.cpp46
-rw-r--r--host/lib/usrp/multi_usrp.cpp11
-rw-r--r--host/lib/usrp/usrp1/io_impl.cpp12
-rw-r--r--host/lib/usrp/usrp1/soft_time_ctrl.cpp4
-rw-r--r--host/lib/usrp/usrp1/usrp1_impl.cpp1
-rw-r--r--host/lib/usrp/usrp2/fw_common.h4
-rw-r--r--host/lib/usrp/usrp2/io_impl.cpp44
-rw-r--r--host/lib/usrp/usrp2/usrp2_iface.cpp13
-rw-r--r--host/lib/usrp/usrp2/usrp2_impl.cpp17
-rw-r--r--host/lib/usrp/usrp2/usrp2_impl.hpp4
-rw-r--r--host/lib/usrp/usrp2/usrp2_regs.hpp12
-rw-r--r--host/tests/convert_test.cpp83
-rw-r--r--host/tests/sph_recv_test.cpp24
-rw-r--r--host/tests/sph_send_test.cpp6
-rw-r--r--host/tests/time_spec_test.cpp6
-rw-r--r--host/usrp_e_utils/usrp-e-loopback.cpp3
-rw-r--r--images/README.txt (renamed from images/README)0
123 files changed, 3954 insertions, 1729 deletions
diff --git a/README.txt b/README.txt
new file mode 100644
index 000000000..64066d522
--- /dev/null
+++ b/README.txt
@@ -0,0 +1,19 @@
+########################################################################
+## Welcome to the USRP source code tree
+########################################################################
+
+host/
+
+ Description: source code for user-space driver
+
+firmware/
+
+ Description: source code for various micro processors
+
+fpga/
+
+ Description: source code for FPGA designs
+
+images/
+
+ Description: package builder for FPGA and firmware images
diff --git a/firmware/README b/firmware/README
deleted file mode 100644
index 251486955..000000000
--- a/firmware/README
+++ /dev/null
@@ -1,6 +0,0 @@
-########################################################################
-# Firmware for USRP devices
-########################################################################
-
-fx2 - firmware for USRP1
-zpu - firmware for USRP2 and N Series
diff --git a/firmware/README.txt b/firmware/README.txt
new file mode 100644
index 000000000..1c233de1d
--- /dev/null
+++ b/firmware/README.txt
@@ -0,0 +1,31 @@
+########################################################################
+# Firmware for USRP devices
+########################################################################
+
+fx2/
+
+ Description: firmware for FX2 device
+
+ Devices: USRP1 and B100
+
+ Tools: sdcc, cmake
+
+ Build Instructions:
+ 1) mkdir <build directory>
+ 2) cd <build directory>
+ 3) cmake <source directory>
+ 4) make
+
+zpu/
+
+ Description: firmware for soft CPU in FPGA
+
+ Devices: USRP2 and N Series
+
+ Tools: zpu-gcc, cmake
+
+ Build Instructions:
+ 1) mkdir <build directory>
+ 2) cd <build directory>
+ 3) cmake <source directory>
+ 4) make
diff --git a/firmware/fx2/b100/usrp_common.c b/firmware/fx2/b100/usrp_common.c
index 4b6dde881..a21353688 100644
--- a/firmware/fx2/b100/usrp_common.c
+++ b/firmware/fx2/b100/usrp_common.c
@@ -32,13 +32,11 @@ init_usrp (void)
CPUCS = bmCLKSPD1; // CPU runs @ 48 MHz
CKCON = 0; // MOVX takes 2 cycles
- // IFCLK is generated internally and runs at 48 MHz; GPIF "master mode"
-
- IFCONFIG = bmIFCLKSRC | bm3048MHZ | bmIFCLKOE | bmIFCLKPOL | bmIFGPIF;
+ // IFCLK is generated internally and runs at 48 MHz, external clk en
+ IFCONFIG = bmIFCLKSRC | bm3048MHZ | bmIFCLKOE;
SYNCDELAY;
- // configure IO ports (B and D are used by GPIF)
-
+ // configure IO ports (B and D are used by slave FIFO)
IOA = bmPORT_A_INITIAL; // Port A initial state
OEA = bmPORT_A_OUTPUTS; // Port A direction register
@@ -53,7 +51,6 @@ init_usrp (void)
// SYNCDELAY;
// configure end points
-
EP1OUTCFG = bmVALID | bmBULK; SYNCDELAY;
EP1INCFG = bmVALID | bmBULK | bmIN; SYNCDELAY;
@@ -63,7 +60,6 @@ init_usrp (void)
EP8CFG = bmVALID | bmBULK | bmDOUBLEBUF | bmIN; SYNCDELAY; // 512 dbl bulk IN
// reset FIFOs
-
FIFORESET = bmNAKALL; SYNCDELAY;
FIFORESET = 2; SYNCDELAY;
FIFORESET = 4; SYNCDELAY;
@@ -72,37 +68,50 @@ init_usrp (void)
FIFORESET = 0; SYNCDELAY;
// configure end point FIFOs
-
- // let core see 0 to 1 transistion of autoout bit
-
+ // let core see 0 to 1 transistion of autoin/out bit
EP2FIFOCFG = bmWORDWIDE; SYNCDELAY;
EP2FIFOCFG = bmAUTOOUT | bmWORDWIDE; SYNCDELAY;
- EP6FIFOCFG = bmZEROLENIN | bmWORDWIDE; SYNCDELAY;
- //EP6FIFOCFG = bmWORDWIDE; SYNCDELAY;
+ EP6FIFOCFG = bmZEROLENIN | bmWORDWIDE; SYNCDELAY;
+ EP6FIFOCFG = bmZEROLENIN | bmAUTOIN | bmWORDWIDE; SYNCDELAY;
EP4FIFOCFG = bmWORDWIDE; SYNCDELAY;
EP4FIFOCFG = bmAUTOOUT | bmWORDWIDE; SYNCDELAY;
- EP8FIFOCFG = bmAUTOIN | bmWORDWIDE; SYNCDELAY;
+ EP8FIFOCFG = bmZEROLENIN | bmWORDWIDE; SYNCDELAY;
+ EP8FIFOCFG = bmZEROLENIN | bmAUTOIN | bmWORDWIDE; SYNCDELAY;
EP0BCH = 0; SYNCDELAY;
-
// arm EP1OUT so we can receive "out" packets (TRM pg 8-8)
-
EP1OUTBC = 0; SYNCDELAY;
- EP2GPIFFLGSEL = 0x00; SYNCDELAY; // For EP2OUT, GPIF uses EF flag
- EP6GPIFFLGSEL = 0x00; SYNCDELAY; // For EP6IN, GPIF uses FF flag
- EP4GPIFFLGSEL = 0x00; SYNCDELAY;
- EP8GPIFFLGSEL = 0x00; SYNCDELAY;
-
- // set autoin length for EP6
- // FIXME should be f(enumeration)
-
+ // set autoin length for EP6/EP8
EP6AUTOINLENH = (512) >> 8; SYNCDELAY; // this is the length for high speed
EP6AUTOINLENL = (512) & 0xff; SYNCDELAY;
-
EP8AUTOINLENH = (32) >> 8; SYNCDELAY;
EP8AUTOINLENL = (32) & 0xff; SYNCDELAY;
+ //set FLAGA, FLAGB, FLAGC, FLAGD to be EP2EF, EP4EF, EP6PF, EP8PF
+ PINFLAGSAB = (bmEP2EF) | (bmEP4EF << 4);
+ PINFLAGSCD = (bmEP6PF) | (bmEP8PF << 4);
+
+ //ok as far as i can tell, DECIS is reversed compared to the FX2 TRM.
+ //p15.34 says DECIS high implements [assert when (fill > level)], observed opposite
+ EP6FIFOPFH = 0x09;
+ SYNCDELAY;
+ EP6FIFOPFL = 0xFD;
+ SYNCDELAY;
+
+// EP2FIFOPFH = 0x08;
+// SYNCDELAY;
+// EP2FIFOPFL = 0x00;
+// SYNCDELAY;
+
+ //assert FIFOEMPTY one cycle sooner so we get it in time at the FPGA
+ EP2FIFOCFG |= bmBIT5;
+
+ //set FIFOPINPOLAR to normal (active low) mode
+ FIFOPINPOLAR = 0x00;
+ SYNCDELAY;
+ PORTACFG = 0x80;
+
init_board ();
}
diff --git a/firmware/fx2/b100/usrp_main.c b/firmware/fx2/b100/usrp_main.c
index 391a6d94f..7c4dd479d 100644
--- a/firmware/fx2/b100/usrp_main.c
+++ b/firmware/fx2/b100/usrp_main.c
@@ -21,7 +21,6 @@
#include "usrp_common.h"
#include "usrp_commands.h"
#include "fpga.h"
-#include "usrp_gpif_inline.h"
#include "timer.h"
#include "i2c.h"
#include "isr.h"
@@ -64,7 +63,12 @@ bit enable_gpif = 0;
#define USRP_HASH_SIZE 16
xdata at USRP_HASH_SLOT_1_ADDR unsigned char hash1[USRP_HASH_SIZE];
-void clear_fpga_data_fifo(void);
+//void clear_fpga_data_fifo(void);
+
+//use the B100 fpga_config_cclk/ext_reset line to reset the FPGA
+void fpga_reset(int level) {
+ bitALTERA_DCLK = level;
+}
static void
get_ep0_data (void)
@@ -75,13 +79,21 @@ get_ep0_data (void)
;
}
-static void initialize_gpif_buffer(int ep) {
- //clear the GPIF buffers on startup to keep crap out of the data path
+static void clear_fifo(int ep) {
FIFORESET = 0x80; SYNCDELAY; //activate NAKALL
FIFORESET = ep; SYNCDELAY;
FIFORESET = 0x00; SYNCDELAY;
}
+void enable_xfers(int enable) {
+ if(enable) {
+ IFCONFIG |= bmIFSLAVE;
+ } else {
+ IFCONFIG &= ~bmIFSLAVE;
+ }
+ set_led_0(enable);
+}
+
/*
* Handle our "Vendor Extension" commands on endpoint 0.
* If we handle this one, return non-zero.
@@ -112,7 +124,7 @@ app_vendor_cmd (void)
case VRQ_FW_COMPAT:
EP0BCH = 0;
- EP0BCL = 2;
+ EP0BCL = 3;
break;
default:
@@ -161,7 +173,7 @@ app_vendor_cmd (void)
break;
case VRQ_FPGA_SET_RESET:
- //fpga_set_reset (wValueL);
+ fpga_reset(wValueL);
break;
case VRQ_I2C_WRITE:
@@ -171,16 +183,15 @@ app_vendor_cmd (void)
break;
case VRQ_RESET_GPIF:
- initialize_gpif_buffer(wValueL);
+ clear_fifo(wValueL);
break;
case VRQ_ENABLE_GPIF:
- enable_gpif = (wValueL != 0) ? 1 : 0;
- set_led_1(enable_gpif);
+ enable_xfers(wValueL);
break;
case VRQ_CLEAR_FPGA_FIFO:
- clear_fpga_data_fifo();
+ //clear_fpga_data_fifo();
break;
default:
@@ -194,125 +205,12 @@ app_vendor_cmd (void)
return 1;
}
-static int short_pkt_state = 0;
-#define SHORT_PACKET_DETECTED (short_pkt_state != bitSHORT_PACKET_SIGNAL)
-
-//yes, this is a little opaque
-//basically this is necessary because while all the logic to inform the FPGA
-//of what we're trying to do via the CTL pins is contained within the flowstates,
-//we need to assert the endpoint select pin one clock cycle before the flowstate starts.
-//this is the job of the wave descriptor. rather than switch between waves, since that
-//involves a little more setup, we just modify the wave table on the fly.
-inline static void setup_wave_data_read(void) {
- GPIF_WAVE_DATA[80] = 0x06;
- GPIF_WAVE_DATA[81] = 0x06;
-}
-
-inline static void setup_wave_ctrl_read(void) {
- GPIF_WAVE_DATA[80] = 0x0E;
- GPIF_WAVE_DATA[81] = 0x0E;
-}
-
-inline static void setup_wave_data_write(void) {
- GPIF_WAVE_DATA[112] = 0x00;
- GPIF_WAVE_DATA[113] = 0x00;
-}
-
-inline static void setup_wave_ctrl_write(void) {
- GPIF_WAVE_DATA[112] = 0x08;
- GPIF_WAVE_DATA[113] = 0x08;
-}
-
-inline static void handle_data_write(void) {
- GPIFTCB1 = 0x01; //SYNCDELAY;
- GPIFTCB0 = 0x00;
- setup_flowstate_data_write ();
- setup_wave_data_write();
- GPIFTRIG = bmGPIF_EP2_START | bmGPIF_WRITE; // start the xfer
- SYNCDELAY;
- while (!(GPIFTRIG & bmGPIF_IDLE));
-}
-
-inline static void handle_ctrl_write(void) {
- GPIFTCB1 = 0x00;
- GPIFTCB0 = 0x10;
- setup_flowstate_ctrl_write ();
- setup_wave_ctrl_write();
- GPIFTRIG = bmGPIF_EP4_START | bmGPIF_WRITE; // start the xfer
- SYNCDELAY;
- while (!(GPIFTRIG & bmGPIF_IDLE));
-}
-
-inline static void handle_data_read(void) {
- GPIFTCB1 = 0x01;
- GPIFTCB0 = 0x00;
- setup_flowstate_data_read ();
- setup_wave_data_read();
- short_pkt_state = bitSHORT_PACKET_SIGNAL;
- GPIFTRIG = bmGPIF_EP6_START | bmGPIF_READ; // start the xfer
- SYNCDELAY;
- while (!(GPIFTRIG & bmGPIF_IDLE));
- INPKTEND = 0x06; // tell USB we filled buffer (6 is our endpoint num)
- SYNCDELAY;
- if(SHORT_PACKET_DETECTED) {
- while(!(EP6CS & bmEPEMPTY)); //wait for packet to send
- INPKTEND = 0x06; //send a ZLP
- //toggle_led_1(); //FIXME DEBUG
- }
-}
-
-inline static void handle_ctrl_read(void) {
- GPIFTCB1 = 0x00;
- GPIFTCB0 = 0x10;
- setup_flowstate_ctrl_read ();
- setup_wave_ctrl_read();
- GPIFTRIG = bmGPIF_EP8_START | bmGPIF_READ; // start the xfer
- SYNCDELAY;
- while (!(GPIFTRIG & bmGPIF_IDLE));
- INPKTEND = 8; // tell USB we filled buffer (8 is our endpoint num)
-}
-
-//clear the FPGA datapath by reading but not submitting, instead clearing the FIFO after each transaction
-void clear_fpga_data_fifo(void) {
- while(fpga_has_data_packet_avail()) {
- GPIFTCB1 = 0x01;
- GPIFTCB0 = 0x00;
- setup_flowstate_data_read ();
- setup_wave_data_read();
- GPIFTRIG = bmGPIF_EP6_START | bmGPIF_READ; // start the xfer
- SYNCDELAY;
- while (!(GPIFTRIG & bmGPIF_IDLE));
- initialize_gpif_buffer(6); //reset the FIFO instead of committing it
- }
-}
-
static void
main_loop (void)
{
while (1){
if (usb_setup_packet_avail ())
usb_handle_setup_packet ();
-
- if(enable_gpif){
- if (fx2_has_ctrl_packet_avail() && fpga_has_room_for_ctrl_packet()) handle_ctrl_write();
- if (fx2_has_room_for_ctrl_packet() && fpga_has_ctrl_packet_avail()) handle_ctrl_read();
-
- //we do this
- if (fx2_has_data_packet_avail() && fpga_has_room_for_data_packet()) handle_data_write();
- if (fx2_has_room_for_data_packet() && fpga_has_data_packet_avail()) handle_data_read();
- //five times so that
- if (fx2_has_data_packet_avail() && fpga_has_room_for_data_packet()) handle_data_write();
- if (fx2_has_room_for_data_packet() && fpga_has_data_packet_avail()) handle_data_read();
- //we can piggyback
- if (fx2_has_data_packet_avail() && fpga_has_room_for_data_packet()) handle_data_write();
- if (fx2_has_room_for_data_packet() && fpga_has_data_packet_avail()) handle_data_read();
- //data transfers
- if (fx2_has_data_packet_avail() && fpga_has_room_for_data_packet()) handle_data_write();
- if (fx2_has_room_for_data_packet() && fpga_has_data_packet_avail()) handle_data_read();
- //without loop overhead
- if (fx2_has_data_packet_avail() && fpga_has_room_for_data_packet()) handle_data_write();
- if (fx2_has_room_for_data_packet() && fpga_has_data_packet_avail()) handle_data_read();
- }
}
}
@@ -363,15 +261,9 @@ patch_usb_descriptors(void)
void
main (void)
{
- enable_gpif = 0;
-
memset (hash1, 0, USRP_HASH_SIZE); // zero fpga bitstream hash. This forces reload
init_usrp ();
- init_gpif ();
-
- // if (UC_START_WITH_GSTATE_OUTPUT_ENABLED)
- //IFCONFIG |= bmGSTATE; // no conflict, start with it on
set_led_0 (0);
set_led_1 (0);
@@ -388,7 +280,6 @@ main (void)
EA = 1; // global interrupt enable
fx2_renumerate (); // simulates disconnect / reconnect
-
- setup_flowstate_common();
+
main_loop ();
}
diff --git a/firmware/fx2/b100/usrp_regs.h b/firmware/fx2/b100/usrp_regs.h
index f6695d9f9..3d65337f5 100644
--- a/firmware/fx2/b100/usrp_regs.h
+++ b/firmware/fx2/b100/usrp_regs.h
@@ -41,8 +41,6 @@
#define bmALTERA_NCONFIG bmBIT1
#define bmALTERA_DATA0 bmBIT3
#define bmALTERA_NSTATUS bmBIT4
-#define bmRESET_FPGA_FIFOS bmBIT7
-
#define bmALTERA_BITS (bmALTERA_DCLK \
| bmALTERA_NCONFIG \
@@ -64,7 +62,6 @@
sbit at PORT_A_ADDR+0 bitALTERA_DCLK; // 0x80 is the bit address of PORT A
sbit at PORT_A_ADDR+1 bitALTERA_NCONFIG;
sbit at PORT_A_ADDR+3 bitALTERA_DATA0;
-sbit at PORT_A_ADDR+6 bitSHORT_PACKET_SIGNAL;
sbit at PORT_C_ADDR+7 bitALTERA_CONF_DONE;
@@ -102,29 +99,4 @@ sbit at PORT_C_ADDR+7 bitALTERA_CONF_DONE;
#define bmPORT_E_OUTPUTS (0)
#define bmPORT_E_INITIAL (0)
-/*
- * FPGA output lines that are tied to FX2 RDYx inputs.
- * These are readable using GPIFREADYSTAT.
- */
-//#define bmFPGA_HAS_SPACE bmBIT0 // usbrdy[0] has room for 512 byte packet
-//#define bmFPGA_PKT_AVAIL bmBIT1 // usbrdy[1] has >= 512 bytes available
-
-#define bmDATA_EMPTY bmBIT0 //data output FIFO has no data ready
-#define bmDATA_FIFO_FULL bmBIT1 //data input FIFO is full
-#define bmCTRL_EMPTY bmBIT2 //control output FIFO has no data ready
-#define bmCTRL_FIFO_FULL bmBIT3 //control input FIFO is full
-
-// #define bmTX_UNDERRUN bmBIT2 // usbrdy[2] D/A ran out of data
-// #define bmRX_OVERRUN bmBIT3 // usbrdy[3] A/D ran out of buffer
-
-/*
- * FPGA input lines that are tied to the FX2 CTLx outputs.
- *
- * These are controlled by the GPIF microprogram...
- */
-// WE bmBIT0 // usbctl[0] write enable
-// RE bmBIT1 // usbctl[1] read enable
-// OE bmBIT2 // usbctl[2] output enable
-// EP bmBIT3 // usbctl[3] endpoint select (data/ctrl)
-
#endif /* _USRP_REV1_REGS_H_ */
diff --git a/firmware/fx2/common/fx2regs.h b/firmware/fx2/common/fx2regs.h
index aa44791d0..acbc0b89e 100644
--- a/firmware/fx2/common/fx2regs.h
+++ b/firmware/fx2/common/fx2regs.h
@@ -91,7 +91,6 @@ EXTERN xdata _AT_(0xE60A) volatile BYTE REVID ; // Chip Revision
EXTERN xdata _AT_(0xE60B) volatile BYTE REVCTL ; // Chip Revision Control
// Endpoint Configuration
-
EXTERN xdata _AT_(0xE610) volatile BYTE EP1OUTCFG ; // Endpoint 1-OUT Configuration
EXTERN xdata _AT_(0xE611) volatile BYTE EP1INCFG ; // Endpoint 1-IN Configuration
EXTERN xdata _AT_(0xE612) volatile BYTE EP2CFG ; // Endpoint 2 Configuration
@@ -654,6 +653,22 @@ sfr at 0xF8 EIP; // EIP Bit Values differ from Reg320
#define bmIFCFG0 bmBIT0
#define bmIFCFGMASK (bmIFCFG0 | bmIFCFG1)
#define bmIFGPIF bmIFCFG1
+#define bmIFSLAVE (bmIFCFG0 | bmIFCFG1)
+
+/* Slave FIFO pin flags configuration bits (PINFLAGS) */
+#define bmINDEXED 0x0 //which fifo selected by FIFOADR
+#define bmEP2PF 0x4
+#define bmEP4PF 0x5
+#define bmEP6PF 0x6
+#define bmEP8PF 0x7
+#define bmEP2EF 0x8
+#define bmEP4EF 0x9
+#define bmEP6EF 0xA
+#define bmEP8EF 0xB
+#define bmEP2FF 0xC
+#define bmEP4FF 0xD
+#define bmEP6FF 0xE
+#define bmEP8FF 0xF
/* EP 2468 FIFO Configuration bits (EP2FIFOCFG,EP4FIFOCFG,EP6FIFOCFG,EP8FIFOCFG) */
#define bmINFM bmBIT6
diff --git a/fix-copyright-years b/fix-copyright-years
deleted file mode 100755
index 97630041b..000000000
--- a/fix-copyright-years
+++ /dev/null
@@ -1,71 +0,0 @@
-#!/usr/bin/env python
-
-import re
-import optparse
-import datetime
-import subprocess
-import multiprocessing
-
-co_line_matcher = re.compile('^.*Copyright (.*) Ettus Research LLC$')
-
-def command(*args): return subprocess.Popen(args, stdout=subprocess.PIPE).communicate()[0]
-
-def get_co_line(lines):
- for i, line in enumerate(lines[:5]):
- if co_line_matcher.match(line): return line, i
- return None, None
-
-def fix_co_years(files, keep_years):
- for file in files:
- print file
- lines = open(file).readlines()
- line, num = get_co_line(lines)
- if line is None: continue
-
- #extract the years from the git history
- log_years = map(
- lambda l: int(l.split()[-2]),
- filter(
- lambda l: l.startswith('Date'),
- command('git', 'log', file).splitlines(),
- ),
- )
- log_years = min(log_years), max(log_years)
-
- #extract years from co string
- try:
- co_years_str = co_line_matcher.match(line).groups()[0]
- co_years = map(int, co_years_str.split('-'))
- co_years = min(co_years), max(co_years)
- except Exception, e:
- print ' format error on line %d: "%s"'%(num, line), e
- continue
-
- #keep years means log years is a superset
- if keep_years: log_years = min(co_years+log_years), max(co_years+log_years)
-
- if log_years != co_years:
- print ' log years: %s != copyright years: %s'%(log_years, co_years)
- year_now = datetime.datetime.now().year
- all_years = min(log_years), max(list(log_years)+[year_now]) #add the current year
- all_years_str = '%s-%s'%all_years
- if all_years[0] == all_years[1]: all_years_str = str(all_years[0])
- new_text = ''.join(lines[:num] + [line.replace(co_years_str, all_years_str)] + lines[num+1:])
- open(file, 'w').write(new_text)
-
-if __name__ == "__main__":
- parser = optparse.OptionParser(usage="usage: %prog [options] path")
- parser.add_option("-k", "--keep", action="store_true", help="keep copyright years", default=False)
- (options, args) = parser.parse_args()
-
- #get recursive list of files in the repo
- files = command('git', 'ls-tree', '--name-only', 'HEAD', '-r', args[0]).splitlines()
-
- #start n+1 processes to handle the files
- num_procs = multiprocessing.cpu_count()
- procs = [multiprocessing.Process(
- target=lambda *files: fix_co_years(files, keep_years=options.keep),
- args=files[num::num_procs],
- ) for num in range(num_procs)]
- map(multiprocessing.Process.start, procs)
- map(multiprocessing.Process.join, procs)
diff --git a/fpga/README b/fpga/README
deleted file mode 100644
index aacafecfd..000000000
--- a/fpga/README
+++ /dev/null
@@ -1,4 +0,0 @@
-This is a placeholder for the fpga code (verilog, makefiles, corgens...)
-
-The layout should have a common library and various top level builds
-and testbenches that are organized hierarchically.
diff --git a/fpga/README.txt b/fpga/README.txt
new file mode 100644
index 000000000..29e891f6d
--- /dev/null
+++ b/fpga/README.txt
@@ -0,0 +1,78 @@
+########################################################################
+## Welcome to the USRP FPGA source code tree
+########################################################################
+
+usrp1/
+
+ Description: generation 1 products
+
+ Devices: USRP classic only
+
+ Tools: Quartus from Altera
+
+ Project file: usrp1/toplevel/usrp_std/
+
+usrp2/
+
+ Description: generation 2 products
+
+ Devices: USRP2, N2XX, B100, E1XX
+
+ Tools: ISE from Xilinx, GNU make
+
+ Build Instructions:
+ 1) ensure that xtclsh is in the $PATH
+ 2) cd usrp2/top/<project-directory>
+ 3) make -f Makefile.<device> bin
+ 4) bin file in build-<device>/*.bin
+
+########################################################################
+## Customizing the DSP
+########################################################################
+
+As part of the USRP FPGA build-framework,
+there are several convenient places for users to insert
+custom DSP modules into the transmit and receive chains.
+
+* before the DDC module
+* after the DDC module
+* replace the DDC module
+* before the DUC module
+* after the DUC module
+* replace of the DUC module
+* as an RX packet engine
+* as an TX packet engine
+
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Customizing the top level makefile
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Each USRP device has a makefile associated with it.
+This makefile contains all of the necessary build rules.
+When making a customized FPGA design,
+start by copying the current makefile for your device.
+Makefiles can be found in the usrp2/top/<dir>/Makefile.*
+
+Edit your new makefile:
+* set BUILD_DIR to a unique directory name
+* set CUSTOM_SRCS for your verilog sources
+* set CUSTOM_DEFS (see section below)
+
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Inserting custom modules
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+CUSTOM_DEFS is a string of space-separate key-value pairs.
+Set the CUSTOM_DEFS variable so the FPGA fabric glue
+will substitute your custom modules into the DSP chain.
+
+Example:
+CUSTOM_DEFS = "TX_ENG0_MODULE=my_tx_engine RX_ENG0_MODULE=my_rx_engine"
+Where my_tx_engine and my_rx_engine are the names of custom verilog modules.
+
+The following module definition keys are possible (X is a DSP number):
+
+* TX_ENG<X>_MODULE: set the module for the transmit chain engine.
+* RX_ENG<X>_MODULE: set the module for the receive chain engine.
+* RX_DSP<X>_MODULE: set the module for the transmit dsp chain.
+* TX_DSP<X>_MODULE: set the module for the receive dsp chain.
+
+Examples of custom modules can be found in usrp2/custom/*.v
diff --git a/fpga/usrp2/control_lib/Makefile.srcs b/fpga/usrp2/control_lib/Makefile.srcs
index 567feacde..6ee7ea262 100644
--- a/fpga/usrp2/control_lib/Makefile.srcs
+++ b/fpga/usrp2/control_lib/Makefile.srcs
@@ -1,5 +1,5 @@
#
-# Copyright 2010 Ettus Research LLC
+# Copyright 2010-2012 Ettus Research LLC
#
##################################################
@@ -54,4 +54,5 @@ settings_bus_16LE.v \
atr_controller16.v \
fifo_to_wb.v \
gpio_atr.v \
+user_settings.v \
))
diff --git a/fpga/usrp2/control_lib/double_buffer_tb.v b/fpga/usrp2/control_lib/double_buffer_tb.v
index a9aae6956..804e8804d 100644
--- a/fpga/usrp2/control_lib/double_buffer_tb.v
+++ b/fpga/usrp2/control_lib/double_buffer_tb.v
@@ -27,7 +27,7 @@ module double_buffer_tb();
reg src_rdy_i = 0;
wire dst_rdy_o;
- wire dst_rdy_i = 1;
+ wire dst_rdy_i = 0;
wire [35:0] data_o;
reg [35:0] data_i;
@@ -46,9 +46,9 @@ module double_buffer_tb();
.data_i(data_i), .src_rdy_i(src_rdy_i), .dst_rdy_o(dst_rdy_o),
.data_o(data_o), .src_rdy_o(src_rdy_o), .dst_rdy_i(dst_rdy_i));
- dspengine_16to8 dspengine_16to8
+ dspengine_8to16 #(.HEADER_OFFSET(1)) dspengine_8to16
(.clk(clk),.reset(rst),.clear(0),
- .set_stb(set_stb), .set_addr(0), .set_data({13'h0,1'b1,18'h00400}),
+ .set_stb(set_stb), .set_addr(0), .set_data(1),
.access_we(access_we), .access_stb(access_stb), .access_ok(access_ok), .access_done(access_done),
.access_skip_read(access_skip_read), .access_adr(access_adr), .access_len(access_len),
.access_dat_i(buf_to_dsp), .access_dat_o(dsp_to_buf));
@@ -69,11 +69,13 @@ module double_buffer_tb();
@(posedge clk);
@(posedge clk);
@(posedge clk);
-
+/*
// Passthrough
$display("Passthrough");
src_rdy_i <= 1;
- data_i <= { 2'b00,1'b0,1'b1,32'hFFFFFFFF};
+ data_i <= { 2'b00,1'b0,1'b1,32'h01234567};
+ @(posedge clk);
+ data_i <= { 2'b00,1'b0,1'b0,32'hFFFFFFFF};
@(posedge clk);
data_i <= { 2'b00,1'b0,1'b0,32'h04050607};
@(posedge clk);
@@ -86,16 +88,18 @@ module double_buffer_tb();
repeat (5)
@(posedge clk);
-
+*/
$display("Enabled");
set_stb <= 1;
@(posedge clk);
set_stb <= 0;
-
+/*
@(posedge clk);
$display("Non-IF Data Passthrough");
src_rdy_i <= 1;
- data_i <= { 2'b00,1'b0,1'b1,32'hC0000000};
+ data_i <= { 2'b00,1'b0,1'b1,32'h89acdef0};
+ @(posedge clk);
+ data_i <= { 2'b00,1'b0,1'b0,32'hC0000000};
@(posedge clk);
data_i <= { 2'b00,1'b0,1'b0,32'h14151617};
@(posedge clk);
@@ -111,7 +115,9 @@ module double_buffer_tb();
$display("No StreamID, No Trailer, Even");
src_rdy_i <= 1;
- data_i <= { 2'b00,1'b0,1'b1,32'h0000FFFF};
+ data_i <= { 2'b00,1'b0,1'b1,32'hAAAAAAAA};
+ @(posedge clk);
+ data_i <= { 2'b00,1'b0,1'b0,32'h0000FFFF};
@(posedge clk);
data_i <= { 2'b00,1'b0,1'b0,32'h01000200};
@(posedge clk);
@@ -139,7 +145,9 @@ module double_buffer_tb();
$display("No StreamID, No Trailer, Odd");
src_rdy_i <= 1;
- data_i <= { 2'b00,1'b0,1'b1,32'h0000FFFF};
+ data_i <= { 2'b00,1'b0,1'b1,32'hBBBBBBBB};
+ @(posedge clk);
+ data_i <= { 2'b00,1'b0,1'b0,32'h0000FFFF};
@(posedge clk);
data_i <= { 2'b00,1'b0,1'b0,32'h11001200};
@(posedge clk);
@@ -159,30 +167,59 @@ module double_buffer_tb();
while(~dst_rdy_o)
@(posedge clk);
-
+*/
+ /*
$display("No StreamID, Trailer, Even");
src_rdy_i <= 1;
- data_i <= { 2'b00,1'b0,1'b1,32'h0400FFFF};
+ data_i <= { 2'b00,1'b0,1'b1,32'hCCCCCCCC};
@(posedge clk);
- data_i <= { 2'b00,1'b0,1'b0,32'h21002200};
+ data_i <= { 2'b00,1'b0,1'b0,32'h0400FFFF};
@(posedge clk);
- data_i <= { 2'b00,1'b0,1'b0,32'h23002400};
+ data_i <= { 2'b00,1'b0,1'b0,32'h21222324};
+ @(posedge clk);
+ data_i <= { 2'b00,1'b0,1'b0,32'h25262728};
src_rdy_i <= 0;
@(posedge clk);
src_rdy_i <= 1;
@(posedge clk);
- data_i <= { 2'b00,1'b0,1'b0,32'h25002600};
+ data_i <= { 2'b00,1'b0,1'b0,32'h292a2b2c};
@(posedge clk);
- data_i <= { 2'b00,1'b0,1'b0,32'h27002800};
+ data_i <= { 2'b00,1'b0,1'b0,32'h2d2e2f30};
@(posedge clk);
- data_i <= { 2'b00,1'b1,1'b0,32'h29002a00};
+ data_i <= { 2'b00,1'b1,1'b0,32'hDEADBEEF};
@(posedge clk);
src_rdy_i <= 0;
@(posedge clk);
-
+*/
+ while(~dst_rdy_o)
+ @(posedge clk);
+/*
+ $display("No StreamID, Trailer, Odd");
+ src_rdy_i <= 1;
+ data_i <= { 2'b00,1'b0,1'b1,32'hDDDDDDDD};
+ @(posedge clk);
+ data_i <= { 2'b00,1'b0,1'b0,32'h0400FFFF};
+ @(posedge clk);
+ data_i <= { 2'b00,1'b0,1'b0,32'h21222324};
+ @(posedge clk);
+ data_i <= { 2'b00,1'b0,1'b0,32'h25262728};
+ src_rdy_i <= 0;
+ @(posedge clk);
+ src_rdy_i <= 1;
+ @(posedge clk);
+ data_i <= { 2'b00,1'b0,1'b0,32'h292a2b2c};
+ @(posedge clk);
+ data_i <= { 2'b00,1'b0,1'b0,32'h2d2e2f30};
+ @(posedge clk);
+ data_i <= { 2'b00,1'b1,1'b0,32'hDEBDBF0D};
+ @(posedge clk);
+ src_rdy_i <= 0;
+ @(posedge clk);
+*/
while(~dst_rdy_o)
@(posedge clk);
+/*
$display("No StreamID, Trailer, Odd");
src_rdy_i <= 1;
data_i <= { 2'b00,1'b0,1'b1,32'h0400FFFF};
@@ -226,23 +263,45 @@ module double_buffer_tb();
while(~dst_rdy_o)
@(posedge clk);
-
+*/
$display("StreamID, Trailer, Odd");
src_rdy_i <= 1;
- data_i <= { 2'b00,1'b0,1'b1,32'h1400FFFF};
+ data_i <= { 2'b00,1'b0,1'b1,32'hABCDEF98};
+ @(posedge clk);
+ data_i <= { 2'b00,1'b0,1'b0,32'h1c034567};
+ @(posedge clk);
+ data_i <= { 2'b00,1'b0,1'b0,32'ha0a1a2a3};
+ @(posedge clk);
+ data_i <= { 2'b00,1'b0,1'b0,32'ha4a5a6a7};
+// src_rdy_i <= 0;
+// @(posedge clk);
+// src_rdy_i <= 1;
+ @(posedge clk);
+ data_i <= { 2'b00,1'b0,1'b0,32'ha8a9aaab};
@(posedge clk);
- data_i <= { 2'b00,1'b0,1'b0,32'ha100a200};
+ data_i <= { 2'b00,1'b0,1'b0,32'hacadaeaf};
+ @(posedge clk);
+ data_i <= { 2'b00,1'b1,1'b0,32'hdeadbeef};
@(posedge clk);
- data_i <= { 2'b00,1'b0,1'b0,32'ha300a400};
src_rdy_i <= 0;
@(posedge clk);
src_rdy_i <= 1;
+ data_i <= { 2'b00,1'b0,1'b1,32'hABCDEF98};
+ @(posedge clk);
+ data_i <= { 2'b00,1'b0,1'b0,32'h1c034567};
+ @(posedge clk);
+ data_i <= { 2'b00,1'b0,1'b0,32'ha0a1a2a3};
+ @(posedge clk);
+ data_i <= { 2'b00,1'b0,1'b0,32'ha4a5a6a7};
+// src_rdy_i <= 0;
+// @(posedge clk);
+// src_rdy_i <= 1;
@(posedge clk);
- data_i <= { 2'b00,1'b0,1'b0,32'ha500a600};
+ data_i <= { 2'b00,1'b0,1'b0,32'ha8a9aaab};
@(posedge clk);
- data_i <= { 2'b00,1'b0,1'b0,32'ha700a800};
+ data_i <= { 2'b00,1'b0,1'b0,32'hacadaeaf};
@(posedge clk);
- data_i <= { 2'b00,1'b1,1'b0,32'hbbb0bbb0};
+ data_i <= { 2'b00,1'b1,1'b0,32'hdeadbeef};
@(posedge clk);
src_rdy_i <= 0;
@(posedge clk);
diff --git a/fpga/usrp2/control_lib/user_settings.v b/fpga/usrp2/control_lib/user_settings.v
new file mode 100644
index 000000000..d87f1de21
--- /dev/null
+++ b/fpga/usrp2/control_lib/user_settings.v
@@ -0,0 +1,63 @@
+//
+// Copyright 2012 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/>.
+//
+
+// User settings bus
+//
+// Provides 8-bit address, 32-bit data write only bus for user settings, consumes to addresses in
+// normal settings bus.
+//
+// Write user address to BASE
+// Write user data to BASE+1
+//
+// The user_set_stb will strobe after data write, must write new address even if same as previous one.
+
+module user_settings
+ #(parameter BASE=0)
+ (input clk,
+ input rst,
+
+ input set_stb,
+ input [7:0] set_addr,
+ input [31:0] set_data,
+
+ output set_stb_user,
+ output [7:0] set_addr_user,
+ output [31:0] set_data_user
+ );
+
+ wire addr_changed, data_changed;
+ reg stb_int;
+
+ setting_reg #(.my_addr(BASE+0),.width(8)) sr_0
+ (.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr),
+ .in(set_data),.out(set_addr_user),.changed(addr_changed) );
+
+ setting_reg #(.my_addr(BASE+1)) sr_1
+ (.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr),
+ .in(set_data),.out(set_data_user),.changed(data_changed) );
+
+ always @(posedge clk)
+ if (rst|set_stb_user)
+ stb_int <= 0;
+ else
+ if (addr_changed)
+ stb_int <= 1;
+
+ assign set_stb_user = stb_int & data_changed;
+
+endmodule // user_settings
+
diff --git a/fpga/usrp2/custom/custom_dsp_rx.v b/fpga/usrp2/custom/custom_dsp_rx.v
new file mode 100644
index 000000000..355adf008
--- /dev/null
+++ b/fpga/usrp2/custom/custom_dsp_rx.v
@@ -0,0 +1,71 @@
+//
+// Copyright 2012 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/>.
+//
+
+//COPY ME, CUSTOMIZE ME...
+
+//The following module effects the IO of the DDC chain.
+//By default, this entire module is a simple pass-through.
+
+//To implement DSP logic before the DDC:
+//Implement custom DSP between frontend and ddc input.
+
+//To implement DSP logic after the DDC:
+//Implement custom DSP between ddc output and baseband.
+
+//To bypass the DDC with custom logic:
+//Implement custom DSP between frontend and baseband.
+
+module custom_dsp_rx
+#(
+ //frontend bus width
+ parameter WIDTH = 24
+)
+(
+ //control signals
+ input clock, //dsp clock
+ input reset, //active high synchronous reset
+ input clear, //active high on packet control init
+ input enable, //active high when streaming enabled
+
+ //user settings bus, controlled through user setting regs API
+ input set_stb, input [7:0] set_addr, input [31:0] set_data,
+
+ //full rate inputs directly from the RX frontend
+ input [WIDTH-1:0] frontend_i,
+ input [WIDTH-1:0] frontend_q,
+
+ //full rate outputs directly to the DDC chain
+ output [WIDTH-1:0] ddc_in_i,
+ output [WIDTH-1:0] ddc_in_q,
+
+ //strobed samples {I16,Q16} from the RX DDC chain
+ input [31:0] ddc_out_sample,
+ input ddc_out_strobe, //high on valid sample
+ output ddc_out_enable, //enables DDC module
+
+ //strobbed baseband samples {I16,Q16} from this module
+ output [31:0] bb_sample,
+ output bb_strobe //high on valid sample
+);
+
+ assign ddc_in_i = frontend_i;
+ assign ddc_in_q = frontend_q;
+ assign bb_sample = ddc_out_sample;
+ assign bb_strobe = ddc_out_strobe;
+ assign ddc_out_enable = enable;
+
+endmodule //custom_dsp_rx
diff --git a/fpga/usrp2/custom/custom_dsp_tx.v b/fpga/usrp2/custom/custom_dsp_tx.v
new file mode 100644
index 000000000..0848a187f
--- /dev/null
+++ b/fpga/usrp2/custom/custom_dsp_tx.v
@@ -0,0 +1,71 @@
+//
+// Copyright 2012 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/>.
+//
+
+//COPY ME, CUSTOMIZE ME...
+
+//The following module effects the IO of the DUC chain.
+//By default, this entire module is a simple pass-through.
+
+//To implement DSP logic before the DUC:
+//Implement custom DSP between baseband and duc input.
+
+//To implement DSP logic after the DUC:
+//Implement custom DSP between duc output and frontend.
+
+//To bypass the DUC with custom logic:
+//Implement custom DSP between baseband and frontend.
+
+module custom_dsp_tx
+#(
+ //frontend bus width
+ parameter WIDTH = 24
+)
+(
+ //control signals
+ input clock, //dsp clock
+ input reset, //active high synchronous reset
+ input clear, //active high on packet control init
+ input enable, //active high when streaming enabled
+
+ //user settings bus, controlled through user setting regs API
+ input set_stb, input [7:0] set_addr, input [31:0] set_data,
+
+ //full rate outputs directly to the TX frontend
+ output [WIDTH-1:0] frontend_i,
+ output [WIDTH-1:0] frontend_q,
+
+ //full rate outputs directly from the DUC chain
+ input [WIDTH-1:0] duc_out_i,
+ input [WIDTH-1:0] duc_out_q,
+
+ //strobed samples {I16,Q16} to the TX DUC chain
+ output [31:0] duc_in_sample,
+ input duc_in_strobe, //this is a backpressure signal
+ output duc_in_enable, //enables DUC module
+
+ //strobbed baseband samples {I16,Q16} to this module
+ input [31:0] bb_sample,
+ output bb_strobe //this is a backpressure signal
+);
+
+ assign frontend_i = duc_out_i;
+ assign frontend_q = duc_out_q;
+ assign duc_in_sample = bb_sample;
+ assign bb_strobe = duc_in_strobe;
+ assign duc_in_enable = enable;
+
+endmodule //custom_dsp_tx
diff --git a/fpga/usrp2/custom/custom_engine_rx.v b/fpga/usrp2/custom/custom_engine_rx.v
new file mode 100644
index 000000000..dfeaad2cd
--- /dev/null
+++ b/fpga/usrp2/custom/custom_engine_rx.v
@@ -0,0 +1,53 @@
+//
+// Copyright 2012 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/>.
+//
+
+//COPY ME, CUSTOMIZE ME...
+
+//The following module is used to re-write receive packets to the host.
+//This module provides a packet-based ram interface for manipulating packets.
+//The user writes a custom engine (state machine) to read the input packet,
+//and to produce a new output packet.
+
+//By default, this entire module is a simple pass-through.
+
+module custom_engine_rx
+#(
+ //buffer size for ram interface engine
+ parameter BUF_SIZE = 10
+)
+(
+ //control signals
+ input clock, input reset, input clear,
+
+ //user settings bus, controlled through user setting regs API
+ input set_stb, input [7:0] set_addr, input [31:0] set_data,
+
+ //ram interface for engine
+ output access_we,
+ output access_stb,
+ input access_ok,
+ output access_done,
+ output access_skip_read,
+ output [BUF_SIZE-1:0] access_adr,
+ input [BUF_SIZE-1:0] access_len,
+ output [35:0] access_dat_o,
+ input [35:0] access_dat_i
+);
+
+ assign access_done = access_ok;
+
+endmodule //custom_engine_rx
diff --git a/fpga/usrp2/custom/custom_engine_tx.v b/fpga/usrp2/custom/custom_engine_tx.v
new file mode 100644
index 000000000..9be728484
--- /dev/null
+++ b/fpga/usrp2/custom/custom_engine_tx.v
@@ -0,0 +1,57 @@
+//
+// Copyright 2012 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/>.
+//
+
+//COPY ME, CUSTOMIZE ME...
+
+//The following module is used to re-write transmit packets from the host.
+//This module provides a packet-based ram interface for manipulating packets.
+//The user writes a custom engine (state machine) to read the input packet,
+//and to produce a new output packet.
+
+//By default, this entire module is a simple pass-through.
+
+module custom_engine_tx
+#(
+ //buffer size for ram interface engine
+ parameter BUF_SIZE = 10,
+
+ //the number of 32bit lines between start of buffer and vita header
+ //the metadata before the header should be preserved by the engine
+ parameter HEADER_OFFSET = 0
+)
+(
+ //control signals
+ input clock, input reset, input clear,
+
+ //user settings bus, controlled through user setting regs API
+ input set_stb, input [7:0] set_addr, input [31:0] set_data,
+
+ //ram interface for engine
+ output access_we,
+ output access_stb,
+ input access_ok,
+ output access_done,
+ output access_skip_read,
+ output [BUF_SIZE-1:0] access_adr,
+ input [BUF_SIZE-1:0] access_len,
+ output [35:0] access_dat_o,
+ input [35:0] access_dat_i
+);
+
+ assign access_done = access_ok;
+
+endmodule //custom_engine_tx
diff --git a/fpga/usrp2/custom/power_trig.v b/fpga/usrp2/custom/power_trig.v
new file mode 100644
index 000000000..b38059030
--- /dev/null
+++ b/fpga/usrp2/custom/power_trig.v
@@ -0,0 +1,130 @@
+//
+// Copyright 2012 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 a power trigger module implemented on top of the custom dsp template.
+// Power triggering is implemented after the existing DDC chain.
+// Triggering is controlled via user settings registers.
+
+// Register 0:
+// threshold for power trigger
+// 32 bit unsigned fixed-point number of some arbitrary scaling
+
+module power_trig
+#(
+ //frontend bus width
+ parameter WIDTH = 24,
+ parameter BASE = 0
+)
+(
+ //control signals
+ input clock, //dsp clock
+ input reset, //active high synchronous reset
+ input clear, //active high on packet control init
+ input enable, //active high when streaming enabled
+
+ //user settings bus, controlled through user setting regs API
+ input set_stb, input [7:0] set_addr, input [31:0] set_data,
+
+ //full rate inputs directly from the RX frontend
+ input [WIDTH-1:0] frontend_i,
+ input [WIDTH-1:0] frontend_q,
+
+ //full rate outputs directly to the DDC chain
+ output [WIDTH-1:0] ddc_in_i,
+ output [WIDTH-1:0] ddc_in_q,
+
+ //strobed samples {I16,Q16} from the RX DDC chain
+ input [31:0] ddc_out_sample,
+ input ddc_out_strobe, //high on valid sample
+ output ddc_out_enable, //enables DDC module
+
+ //strobbed baseband samples {I16,Q16} from this module
+ output [31:0] bb_sample,
+ output bb_strobe //high on valid sample
+);
+
+ //leave frontend tied to existing ddc chain
+ assign ddc_in_i = frontend_i;
+ assign ddc_in_q = frontend_q;
+
+ //ddc enable remains tied to global enable
+ assign ddc_out_enable = enable;
+
+ //below we implement a power trigger between baseband samples and ddc output...
+
+ reg [8:0] wr_addr;
+ wire [8:0] rd_addr;
+ reg triggered, triggerable;
+ wire trigger;
+
+ wire [31:0] delayed_sample;
+ wire [31:0] thresh;
+
+ setting_reg #(.my_addr(BASE+0)) sr_0
+ (.clk(clk),.rst(reset),.strobe(set_stb),.addr(set_addr),
+ .in(set_data),.out(thresh),.changed());
+
+ assign rd_addr = wr_addr + 1; // FIXME adjustable delay
+
+ ram_2port #(.DWIDTH(32),.AWIDTH(9)) delay_line
+ (.clka(clk),.ena(1),.wea(ddc_out_strobe),.addra(wr_addr),.dia(ddc_out_sample),.doa(),
+ .clkb(clk),.enb(ddc_out_strobe),.web(1'b0),.addrb(rd_addr),.dib(32'hFFFF),.dob(delayed_sample));
+
+ always @(posedge clock)
+ if(reset | ~enable)
+ wr_addr <= 0;
+ else
+ if(ddc_out_strobe)
+ wr_addr <= wr_addr + 1;
+
+ always @(posedge clock)
+ if(reset | ~enable)
+ triggerable <= 0;
+ else if(wr_addr == 9'h1FF) // Wait till we're nearly full
+ triggerable <= 1;
+
+
+ reg stb_d1, stb_d2;
+ always @(posedge clock) stb_d1 <= ddc_out_strobe;
+ always @(posedge clock) stb_d2 <= stb_d1;
+
+ assign bb_sample = delayed_sample;
+ assign bb_strobe = stb_d1 & triggered;
+
+ // Compute Mag
+ wire [17:0] mult_in = stb_d1 ? { ddc_out_sample[15],ddc_out_sample[15:0], 1'b0 } :
+ { ddc_out_sample[31], ddc_out_sample[31:16], 1'b0 };
+ wire [35:0] prod;
+ reg [31:0] sum;
+
+ MULT18X18S mult (.P(prod), .A(mult_in), .B(mult_in), .C(clock), .CE(ddc_out_strobe | stb_d1), .R(reset) );
+
+ always @(posedge clock)
+ if(stb_d1)
+ sum <= prod[35:4];
+ else if(stb_d2)
+ sum <= sum + prod[35:4];
+
+ always @(posedge clock)
+ if(reset | ~enable | ~triggerable)
+ triggered <= 0;
+ else if(trigger)
+ triggered <= 1;
+
+ assign trigger = (sum > thresh);
+
+endmodule // power_trig
diff --git a/fpga/usrp2/custom/power_trig_tb.v b/fpga/usrp2/custom/power_trig_tb.v
new file mode 100644
index 000000000..b8f3385ce
--- /dev/null
+++ b/fpga/usrp2/custom/power_trig_tb.v
@@ -0,0 +1,71 @@
+//
+// Copyright 2012 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 power_trig_tb();
+ initial $dumpfile("power_trig_tb.vcd");
+ initial $dumpvars(0,power_trig_tb);
+
+ reg clk = 0;
+ always #10 clk <= ~clk;
+ reg rst = 1;
+ initial #100 rst <= 0;
+
+ initial
+ begin
+ set_stb <= 0;
+ #1000;
+ set_stb <= 1;
+ end
+
+ reg [31:0] sample_in;
+ reg strobe_in;
+ wire [31:0] sample_out;
+ wire strobe_out;
+ reg set_stb, run;
+
+ power_trig #(.BASE(0)) power_trig
+ (.clk(clk), .reset(rst), .enable(1),
+ .set_stb(set_stb), .set_addr(0), .set_data(32'h000B_B000),
+ .run(run),
+
+ .ddc_out_sample(sample_in), .ddc_out_strobe(strobe_in),
+ .bb_sample(sample_out), .bb_strobe(strobe_out));
+
+ initial sample_in <= 32'h0100_0300;
+
+ always @(posedge clk)
+ if(~strobe_in)
+ sample_in <= sample_in + 32'h0001_0001;
+
+ initial
+ #100000 $finish;
+
+ initial
+ begin
+ run <= 0;
+ #2000 run <= 1;
+ #30000 run <= 0;
+ end
+
+ always @(posedge clk)
+ if(rst | ~run)
+ strobe_in <= 0;
+ else
+ strobe_in <= ~strobe_in;
+
+endmodule // power_trig_tb
diff --git a/fpga/usrp2/gpif/Makefile.srcs b/fpga/usrp2/gpif/Makefile.srcs
index bf2b7f74d..06cde8afa 100644
--- a/fpga/usrp2/gpif/Makefile.srcs
+++ b/fpga/usrp2/gpif/Makefile.srcs
@@ -11,4 +11,5 @@ gpif_wr.v \
gpif_rd.v \
packet_reframer.v \
packet_splitter.v \
+slave_fifo.v \
))
diff --git a/fpga/usrp2/gpif/packet_reframer.v b/fpga/usrp2/gpif/packet_reframer.v
index 923d499ae..8bb8a3678 100644
--- a/fpga/usrp2/gpif/packet_reframer.v
+++ b/fpga/usrp2/gpif/packet_reframer.v
@@ -1,5 +1,5 @@
//
-// Copyright 2011 Ettus Research LLC
+// Copyright 2011-2012 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
@@ -16,7 +16,7 @@
//
-// Join vita packets longer than one GPIF frame, drop padding on short frames
+// Join vita packets longer than one GPIF frame
module packet_reframer
(input clk, input reset, input clear,
@@ -25,18 +25,20 @@ module packet_reframer
output dst_rdy_o,
output [18:0] data_o,
output src_rdy_o,
- input dst_rdy_i);
+ input dst_rdy_i,
+ output reg state,
+ output eof_out,
+ output reg [15:0] length);
- reg [1:0] state;
- reg [15:0] length;
+ //reg state;
+ //reg [15:0] length;
localparam RF_IDLE = 0;
localparam RF_PKT = 1;
- localparam RF_DUMP = 2;
always @(posedge clk)
if(reset | clear)
- state <= 0;
+ state <= RF_IDLE;
else
if(src_rdy_i & dst_rdy_i)
case(state)
@@ -47,26 +49,16 @@ module packet_reframer
end
RF_PKT :
begin
- if(length == 2)
- if(data_i[17])
- state <= RF_IDLE;
- else
- state <= RF_DUMP;
- else
- length <= length - 1;
+ if(eof_out) state <= RF_IDLE;
+ length <= length - 1;
end
- RF_DUMP :
- if(data_i[17])
- state <= RF_IDLE;
- default :
- state<= RF_IDLE;
endcase // case (state)
assign dst_rdy_o = dst_rdy_i; // this is a little pessimistic but ok
- assign src_rdy_o = src_rdy_i & (state != RF_DUMP);
+ assign src_rdy_o = src_rdy_i;
wire occ_out = 0;
- wire eof_out = (state == RF_PKT) & (length == 2);
+ assign eof_out = (state == RF_PKT) & (length == 2);
wire sof_out = (state == RF_IDLE);
wire [15:0] data_out = data_i[15:0];
assign data_o = {occ_out, eof_out, sof_out, data_out};
diff --git a/fpga/usrp2/gpif/slave_fifo.v b/fpga/usrp2/gpif/slave_fifo.v
new file mode 100644
index 000000000..10740942b
--- /dev/null
+++ b/fpga/usrp2/gpif/slave_fifo.v
@@ -0,0 +1,467 @@
+//
+// Copyright 2011-2012 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 is a FIFO master interface for the FX2 in "slave fifo" mode.
+
+module slave_fifo
+ #(parameter TXFIFOSIZE = 12, parameter RXFIFOSIZE = 12)
+ (// GPIF signals
+ input gpif_clk, input gpif_rst,
+ inout [15:0] gpif_d,
+ input [3:0] gpif_ctl,
+ output sloe, output slrd, output slwr, output pktend, output [1:0] fifoadr,
+
+ // Wishbone signals
+ input wb_clk, input wb_rst,
+ output [15:0] wb_adr_o, output [15:0] wb_dat_mosi, input [15:0] wb_dat_miso,
+ output [1:0] wb_sel_o, output wb_cyc_o, output wb_stb_o, output wb_we_o, input wb_ack_i,
+ input [7:0] triggers,
+
+ input dsp_rx_run,
+
+ // FIFO interface
+ input fifo_clk, input fifo_rst, input clear_tx, input clear_rx,
+ output [35:0] tx_data_o, output tx_src_rdy_o, input tx_dst_rdy_i,
+ input [35:0] rx_data_i, input rx_src_rdy_i, output rx_dst_rdy_o,
+ input [35:0] tx_err_data_i, input tx_err_src_rdy_i, output tx_err_dst_rdy_o,
+ output tx_underrun, output rx_overrun,
+
+ input [15:0] test_len, input [7:0] test_rate, input [3:0] test_ctrl,
+ output [31:0] debug0, output [31:0] debug1
+ );
+
+ // inputs to FPGA (all active low)
+ wire FX2_DE = ~gpif_ctl[0]; //EP2 FX2 FIFO empty (FLAGA)
+ wire FX2_CE = ~gpif_ctl[1]; //EP4 FX2 FIFO empty (FLAGB)
+ wire FX2_DF = ~gpif_ctl[2]; //EP6 FX2 FIFO full (FLAGC)
+ wire FX2_CF = ~gpif_ctl[3]; //EP8 FX2 FIFO full (FLAGD)
+
+ wire [17:0] gpif_d_out_ctrl, gpif_d_out_data, gpif_d_out;
+
+ // ////////////////////////////////////////////////////////////////////
+ // GPIF bus master state machine
+
+ //transfer size for GPIF data. this can be anything really, it's specified only for
+ //fairness in bus sharing. 256 lines is 512 bytes over the wire, half the size of
+ //the double buffers in B100/B150. this should probably be a toplevel parameter or even
+ //a settings register value.
+ localparam data_transfer_size = 256;
+ localparam ctrl_transfer_size = 16; //probably unnecessary since ctrl xfers won't back up
+
+ // state machine i/o to four fifos
+ //tx
+ wire ctrl_tx_dst_rdy; //sm input, ctrl tx path has space
+ wire ctrl_tx_src_rdy; //sm output, ctrl tx path enable
+ reg data_tx_dst_rdy; //sm input, data tx path has space
+ wire data_tx_src_rdy; //sm output, data tx path enable
+
+ //rx
+ wire ctrl_rx_dst_rdy; //sm output, ctrl rx path enable
+ wire ctrl_rx_src_rdy; //sm input, ctrl rx path has space
+ wire data_rx_dst_rdy; //sm output, data rx path enable
+ wire data_rx_src_rdy; //sm input, data rx path has space
+
+ reg [9:0] transfer_count; //number of lines (a line is 16 bits) in active transfer
+
+ wire sop, eop; //SOP/EOP markers for TX data packets
+
+ reg pktend_latch;
+
+ reg [3:0] state; //state machine current state
+ localparam STATE_IDLE = 0;
+ localparam STATE_DATA_RX = 5;
+ localparam STATE_DATA_TX = 3;
+ localparam STATE_CTRL_RX = 6;
+ localparam STATE_CTRL_TX = 9;
+ localparam STATE_DATA_TX_SLOE = 2;
+ localparam STATE_CTRL_TX_SLOE = 8;
+ localparam STATE_DATA_RX_ADR = 1;
+ localparam STATE_CTRL_RX_ADR = 4;
+ localparam STATE_PKTEND = 7;
+
+ //logs the last bus user for xfer fairness
+ //we only care about data rx vs. tx since ctrl pkts are so short
+ reg last_data_bus_hog;
+ localparam BUS_HOG_RX = 0;
+ localparam BUS_HOG_TX = 1;
+
+ // //////////////////////////////////////////////////////////////
+ // FX2 slave FIFO bus master state machine
+ //
+ always @(posedge gpif_clk)
+ if(gpif_rst)
+ state <= STATE_IDLE;
+ else
+ begin
+ case (state)
+ STATE_IDLE:
+ begin
+ transfer_count <= 0;
+ //handle transitions to other states
+ if(ctrl_tx_dst_rdy & ~FX2_CE) //if there's room in the ctrl fifo and the FX2 has ctrl data
+ state <= STATE_CTRL_TX_SLOE;
+ else if(ctrl_rx_src_rdy & ~FX2_CF) //if the ctrl fifo has data and the FX2 isn't full
+ state <= STATE_CTRL_RX_ADR;
+ else if(data_tx_dst_rdy & ~FX2_DE & last_data_bus_hog == BUS_HOG_RX) //if there's room in the data fifo and the FX2 has data
+ state <= STATE_DATA_TX_SLOE;
+ else if(data_rx_src_rdy & ~FX2_DF & last_data_bus_hog == BUS_HOG_TX) //if the data fifo has data and the FX2 isn't full
+ state <= STATE_DATA_RX_ADR;
+ else if(data_tx_dst_rdy & ~FX2_DE)
+ state <= STATE_DATA_TX_SLOE;
+ else if(data_rx_src_rdy & ~FX2_DF)
+ state <= STATE_DATA_RX_ADR;
+ else if(~data_rx_src_rdy & ~dsp_rx_run & pktend_latch & ~FX2_DF)
+ state <= STATE_PKTEND;
+
+ if(data_rx_src_rdy)
+ pktend_latch <= 1;
+ end
+
+ STATE_DATA_TX_SLOE: //just to assert SLOE one cycle before SLRD
+ state <= STATE_DATA_TX;
+ STATE_CTRL_TX_SLOE:
+ state <= STATE_CTRL_TX;
+
+ STATE_DATA_RX_ADR: //just to assert FIFOADR one cycle before SLWR
+ state <= STATE_DATA_RX;
+ STATE_CTRL_RX_ADR:
+ state <= STATE_CTRL_RX;
+
+ STATE_DATA_RX:
+ begin
+ if((transfer_count == data_transfer_size) | FX2_DF | (~data_rx_src_rdy))
+ state <= STATE_IDLE;
+
+ transfer_count <= transfer_count + 1;
+ last_data_bus_hog <= BUS_HOG_RX;
+ end
+
+ STATE_PKTEND:
+ begin
+ state <= STATE_IDLE;
+ pktend_latch <= 0;
+ end
+
+ STATE_DATA_TX:
+ begin
+ if((transfer_count == data_transfer_size) | FX2_DE )/*| (~data_tx_dst_rdy))*/
+ state <= STATE_IDLE;
+ transfer_count <= transfer_count + 1;
+ last_data_bus_hog <= BUS_HOG_TX;
+ end
+ STATE_CTRL_RX:
+ begin
+ if(FX2_CF | (~ctrl_rx_src_rdy))
+ state <= STATE_IDLE;
+ transfer_count <= transfer_count + 1;
+ end
+ STATE_CTRL_TX:
+ begin
+ if(FX2_CE | (~ctrl_tx_dst_rdy))
+ state <= STATE_IDLE;
+ transfer_count <= transfer_count + 1;
+ end
+ endcase
+ end
+
+ // ///////////////////////////////////////////////////////////////////
+ // fifo signal assignments and enables
+
+ //enable fifos
+ assign data_rx_dst_rdy = (state == STATE_DATA_RX);
+ assign data_tx_src_rdy = (state == STATE_DATA_TX);
+ assign ctrl_rx_dst_rdy = (state == STATE_CTRL_RX);
+ assign ctrl_tx_src_rdy = (state == STATE_CTRL_TX);
+
+ //tx framing (this is super suspect)
+ //eop should be used only to set the EOP bit going into FIFOs
+ wire eop_data, eop_ctrl;
+ assign sop = (transfer_count == 0);
+ assign eop_data = (transfer_count == (data_transfer_size-1));
+ assign eop_ctrl = (transfer_count == (ctrl_transfer_size-1));
+ assign eop = (state == STATE_DATA_TX) ? eop_data : eop_ctrl;
+
+ // ////////////////////////////////////////////////////////////////////
+ // set GPIF pins
+
+ //set fifoadr to the appropriate endpoint
+ // {0,0}: EP2, data TX from host
+ // {0,1}: EP4, ctrl TX from host
+ // {1,0}: EP6, data RX to host
+ // {1,1}: EP8, ctrl RX to host
+ assign fifoadr = {(state == STATE_DATA_RX) | (state == STATE_CTRL_RX) | (state == STATE_DATA_RX_ADR) | (state == STATE_CTRL_RX_ADR) | (state == STATE_PKTEND),
+ (state == STATE_CTRL_RX) | (state == STATE_CTRL_RX_ADR) | (state == STATE_CTRL_TX) | (state == STATE_CTRL_TX_SLOE)};
+ //set sloe, slwr, slrd (all active low)
+ //SLOE gets asserted when we want data from the FX2; i.e., TX mode
+ assign sloe = ~{(state == STATE_DATA_TX) | (state == STATE_CTRL_TX) | (state == STATE_DATA_TX_SLOE) | (state == STATE_CTRL_TX_SLOE)};
+ //"read" and "write" here are from the master's point of view;
+ //so "read" means "transmit" and "write" means "receive"
+ assign slwr = ~{(state == STATE_DATA_RX) | (state == STATE_CTRL_RX)};
+ assign slrd = ~{(state == STATE_DATA_TX) | (state == STATE_CTRL_TX)};
+
+ wire pktend_ctrl, pktend_data;
+ assign pktend_ctrl = ((~ctrl_rx_src_rdy | gpif_d_out_ctrl[17]) & (state == STATE_CTRL_RX));
+ assign pktend_data = (state == STATE_PKTEND);
+ assign pktend = ~(pktend_ctrl | pktend_data);
+
+ //mux between ctrl/data RX data out based on endpoint selection
+ assign gpif_d_out = fifoadr[0] ? gpif_d_out_ctrl : gpif_d_out_data;
+ // GPIF output data lines, tristate
+ assign gpif_d = sloe ? gpif_d_out : 16'bz;
+
+ // ////////////////////////////////////////////////////////////////////
+ // TX Data Path
+
+ wire [18:0] tx19_data;
+ wire tx19_src_rdy, tx19_dst_rdy;
+ wire [35:0] tx36_data;
+ wire tx36_src_rdy, tx36_dst_rdy;
+ wire [17:0] data_tx_int;
+ wire tx_src_rdy_int, tx_dst_rdy_int;
+
+ wire [15:0] wr_fifo_space;
+
+ always @(posedge gpif_clk)
+ if(gpif_rst)
+ data_tx_dst_rdy <= 0;
+ else
+ data_tx_dst_rdy <= wr_fifo_space >= 256;
+
+ fifo_cascade #(.WIDTH(18), .SIZE(12)) wr_fifo
+ (.clk(gpif_clk), .reset(gpif_rst), .clear(clear_tx),
+ .datain({eop,sop,gpif_d}), .src_rdy_i(data_tx_src_rdy), .dst_rdy_o(/*data_tx_dst_rdy*/), .space(wr_fifo_space),
+ .dataout(data_tx_int), .src_rdy_o(tx_src_rdy_int), .dst_rdy_i(tx_dst_rdy_int), .occupied());
+
+ fifo_2clock_cascade #(.WIDTH(18), .SIZE(4)) wr_fifo_2clk
+ (.wclk(gpif_clk), .datain(data_tx_int), .src_rdy_i(tx_src_rdy_int), .dst_rdy_o(tx_dst_rdy_int), .space(),
+ .rclk(fifo_clk), .dataout(tx19_data[17:0]), .src_rdy_o(tx19_src_rdy), .dst_rdy_i(tx19_dst_rdy), .occupied(),
+ .arst(fifo_rst));
+
+ assign tx19_data[18] = 1'b0;
+
+ // join vita packets which are longer than one frame, drop frame padding
+ wire [18:0] refr_data;
+ wire refr_src_rdy, refr_dst_rdy;
+ wire refr_state;
+ wire refr_eof;
+ wire [15:0] refr_len;
+
+ packet_reframer tx_packet_reframer
+ (.clk(fifo_clk), .reset(fifo_rst), .clear(clear_tx),
+ .data_i(tx19_data), .src_rdy_i(tx19_src_rdy), .dst_rdy_o(tx19_dst_rdy),
+ .data_o(refr_data), .src_rdy_o(refr_src_rdy), .dst_rdy_i(refr_dst_rdy),
+ .state(refr_state), .eof_out(refr_eof), .length(refr_len));
+
+ fifo19_to_fifo36 #(.LE(1)) f19_to_f36
+ (.clk(fifo_clk), .reset(fifo_rst), .clear(clear_tx),
+ .f19_datain(refr_data), .f19_src_rdy_i(refr_src_rdy), .f19_dst_rdy_o(refr_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
+ (.clk(fifo_clk), .reset(fifo_rst), .clear(clear_tx),
+ .datain(tx36_data), .src_rdy_i(tx36_src_rdy), .dst_rdy_o(tx36_dst_rdy),
+ .dataout(tx_data_o), .src_rdy_o(tx_src_rdy_o), .dst_rdy_i(tx_dst_rdy_i));
+
+ // ////////////////////////////////////////////
+ // RX Data Path
+
+ wire [35:0] rx36_data;
+ wire rx36_src_rdy, rx36_dst_rdy;
+ wire [18:0] rx19_data;
+ wire rx19_src_rdy, rx19_dst_rdy;
+ wire [15:0] rxfifospace;
+
+ //deep 36 bit wide input fifo buffers from DSP
+ fifo_cascade #(.WIDTH(36), .SIZE(8)) rx_fifo36
+ (.clk(fifo_clk), .reset(fifo_rst), .clear(clear_rx),
+ .datain(rx_data_i), .src_rdy_i(rx_src_rdy_i), .dst_rdy_o(rx_dst_rdy_o),
+ .dataout(rx36_data), .src_rdy_o(rx36_src_rdy), .dst_rdy_i(rx36_dst_rdy));
+
+ //convert to fifo19
+ fifo36_to_fifo19 #(.LE(1)) f36_to_f19
+ (.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(rx19_data), .f19_src_rdy_o(rx19_src_rdy), .f19_dst_rdy_i(rx19_dst_rdy) );
+
+ wire [18:0] data_rx_int;
+ wire rx_src_rdy_int, rx_dst_rdy_int;
+ //clock domain crossing fifo for RX data
+ fifo_2clock_cascade #(.WIDTH(19), .SIZE(4)) rd_fifo_2clk
+ (.wclk(fifo_clk), .datain(rx19_data), .src_rdy_i(rx19_src_rdy), .dst_rdy_o(rx19_dst_rdy), .space(),
+ .rclk(~gpif_clk), .dataout(data_rx_int), .src_rdy_o(rx_src_rdy_int), .dst_rdy_i(rx_dst_rdy_int), .occupied(),
+ .arst(fifo_rst));
+
+ //rd_fifo buffers writes to the 2clock fifo above
+ fifo_cascade #(.WIDTH(19), .SIZE(RXFIFOSIZE)) rd_fifo
+ (.clk(~gpif_clk), .reset(gpif_rst), .clear(clear_rx),
+ .datain(data_rx_int), .src_rdy_i(rx_src_rdy_int), .dst_rdy_o(rx_dst_rdy_int), .space(rxfifospace),
+ .dataout(gpif_d_out_data), .src_rdy_o(data_rx_src_rdy), .dst_rdy_i(data_rx_dst_rdy), .occupied());
+
+ // ////////////////////////////////////////////////////////////////////
+ // FIFO to Wishbone interface
+
+ wire [18:0] resp_data, resp_int;
+ wire resp_src_rdy, resp_dst_rdy;
+ wire resp_src_rdy_int, resp_dst_rdy_int;
+
+ wire [18:0] tx_err19_data;
+ wire tx_err19_src_rdy, tx_err19_dst_rdy;
+
+ wire [18:0] ctrl_data;
+ wire ctrl_src_rdy, ctrl_dst_rdy;
+
+ fifo_to_wb fifo_to_wb
+ (.clk(fifo_clk), .reset(fifo_rst), .clear(0),
+ .data_i(ctrl_data), .src_rdy_i(ctrl_src_rdy), .dst_rdy_o(ctrl_dst_rdy),
+ .data_o(resp_int), .src_rdy_o(resp_src_rdy_int), .dst_rdy_i(resp_dst_rdy_int),
+ .wb_adr_o(wb_adr_o), .wb_dat_mosi(wb_dat_mosi), .wb_dat_miso(wb_dat_miso), .wb_sel_o(wb_sel_o),
+ .wb_cyc_o(wb_cyc_o), .wb_stb_o(wb_stb_o), .wb_we_o(wb_we_o), .wb_ack_i(wb_ack_i),
+ .triggers(triggers),
+ .debug0(), .debug1());
+
+ // ////////////////////////////////////////////////////////////////////
+ // TX CTRL PATH (ctrl commands into Wishbone)
+
+ //how does this use fifo_clk instead of wb_clk
+ //answer: on b100 fifo clk IS wb clk
+ fifo_2clock_cascade #(.WIDTH(19), .SIZE(4)) ctrl_fifo_2clk
+ (.wclk(gpif_clk), .datain({1'b0,eop,sop,gpif_d}),
+ .src_rdy_i(ctrl_tx_src_rdy), .dst_rdy_o(ctrl_tx_dst_rdy), .space(),
+ .rclk(fifo_clk), .dataout(ctrl_data),
+ .src_rdy_o(ctrl_src_rdy), .dst_rdy_i(ctrl_dst_rdy), .occupied(),
+ .arst(fifo_rst));
+
+ // ////////////////////////////////////////////////////////////////////
+ // RX CTRL PATH (async packets, ctrl response data)
+
+ //tx_err_data_i is the 36wide tx async err data clocked on fifo_clk
+ fifo36_to_fifo19 #(.LE(1)) f36_to_f19_txerr
+ (.clk(fifo_clk), .reset(fifo_rst), .clear(clear_rx),
+ .f36_datain(tx_err_data_i), .f36_src_rdy_i(tx_err_src_rdy_i), .f36_dst_rdy_o(tx_err_dst_rdy_o),
+ .f19_dataout(tx_err19_data), .f19_src_rdy_o(tx_err19_src_rdy), .f19_dst_rdy_i(tx_err19_dst_rdy) );
+
+ //mux FIFO-to-WB along with async tx err pkts into one ctrl resp fifo
+ //how is this clocked on wb_clk?
+ fifo19_mux #(.prio(0)) mux_err_stream
+ (.clk(wb_clk), .reset(wb_rst), .clear(clear_rx),
+ .data0_i(resp_int), .src0_rdy_i(resp_src_rdy_int), .dst0_rdy_o(resp_dst_rdy_int),
+ .data1_i(tx_err19_data), .src1_rdy_i(tx_err19_src_rdy), .dst1_rdy_o(tx_err19_dst_rdy),
+ .data_o(resp_data), .src_rdy_o(resp_src_rdy), .dst_rdy_i(resp_dst_rdy));
+
+ //clock domain crossing cascade fifo for mux_err_stream to get from wb_clk to gpif_clk
+ //the output of this fifo is CTRL DATA PENDING FOR GPIF
+ fifo_2clock_cascade #(.WIDTH(18), .SIZE(4)) resp_fifo_2clk
+ (.wclk(wb_clk), .datain(resp_data[17:0]), .src_rdy_i(resp_src_rdy), .dst_rdy_o(resp_dst_rdy), .space(),
+ .rclk(~gpif_clk), .dataout(gpif_d_out_ctrl),
+ .src_rdy_o(ctrl_rx_src_rdy), .dst_rdy_i(ctrl_rx_dst_rdy), .occupied(),
+ .arst(wb_rst));
+
+
+ // ////////////////////////////////////////////////////////////////////
+ // Debug support, timed and loopback
+ // RX side muxes test data into the same stream
+
+ ///////////////////////////////////////////////////////////////////////
+ // debug lines
+ wire [31:0] debug_rd, debug_wr, debug_split0, debug_split1;
+
+ wire [35:0] timedrx_data, loopbackrx_data, testrx_data;
+ wire [35:0] timedtx_data, loopbacktx_data, testtx_data;
+ wire timedrx_src_rdy, timedrx_dst_rdy, loopbackrx_src_rdy, loopbackrx_dst_rdy,
+ testrx_src_rdy, testrx_dst_rdy;
+ wire timedtx_src_rdy, timedtx_dst_rdy, loopbacktx_src_rdy, loopbacktx_dst_rdy,
+ testtx_src_rdy, testtx_dst_rdy;
+ wire timedrx_src_rdy_int, timedrx_dst_rdy_int, timedtx_src_rdy_int, timedtx_dst_rdy_int;
+
+ wire [31:0] total, crc_err, seq_err, len_err;
+ wire sel_testtx = test_ctrl[0];
+ wire sel_loopbacktx = test_ctrl[1];
+ wire pkt_src_enable = test_ctrl[2];
+ wire pkt_sink_enable = test_ctrl[3];
+/*
+ fifo36_mux rx_test_mux_lvl_1
+ (.clk(fifo_clk), .reset(fifo_rst), .clear(clear_rx),
+ .data0_i(timedrx_data), .src0_rdy_i(timedrx_src_rdy), .dst0_rdy_o(timedrx_dst_rdy),
+ .data1_i(loopbackrx_data), .src1_rdy_i(loopbackrx_src_rdy), .dst1_rdy_o(loopbackrx_dst_rdy),
+ .data_o(testrx_data), .src_rdy_o(testrx_src_rdy), .dst_rdy_i(testrx_dst_rdy));
+
+ fifo36_mux rx_test_mux_lvl_2
+ (.clk(fifo_clk), .reset(fifo_rst), .clear(clear_rx),
+ .data0_i(testrx_data), .src0_rdy_i(testrx_src_rdy), .dst0_rdy_o(testrx_dst_rdy),
+ .data1_i(rx_data_i), .src1_rdy_i(rx_src_rdy_i), .dst1_rdy_o(rx_dst_rdy_o),
+ .data_o(rx_data), .src_rdy_o(rx_src_rdy), .dst_rdy_i(rx_dst_rdy));
+
+ fifo_short #(.WIDTH(36)) loopback_fifo
+ (.clk(fifo_clk), .reset(fifo_rst), .clear(clear_tx | clear_rx),
+ .datain(loopbacktx_data), .src_rdy_i(loopbacktx_src_rdy), .dst_rdy_o(loopbacktx_dst_rdy),
+ .dataout(loopbackrx_data), .src_rdy_o(loopbackrx_src_rdy), .dst_rdy_i(loopbackrx_dst_rdy));
+
+ // Crossbar used as a demux for switching TX stream to main DSP or to test logic
+ crossbar36 tx_crossbar_lvl_1
+ (.clk(fifo_clk), .reset(fifo_rst), .clear(clear_tx),
+ .cross(sel_testtx),
+ .data0_i(tx_data), .src0_rdy_i(tx_src_rdy), .dst0_rdy_o(tx_dst_rdy),
+ .data1_i(tx_data), .src1_rdy_i(1'b0), .dst1_rdy_o(), // No 2nd input
+ .data0_o(tx_data_o), .src0_rdy_o(tx_src_rdy_o), .dst0_rdy_i(tx_dst_rdy_i),
+ .data1_o(testtx_data), .src1_rdy_o(testtx_src_rdy), .dst1_rdy_i(testtx_dst_rdy) );
+
+ crossbar36 tx_crossbar_lvl_2
+ (.clk(fifo_clk), .reset(fifo_rst), .clear(clear_tx),
+ .cross(sel_loopbacktx),
+ .data0_i(testtx_data), .src0_rdy_i(testtx_src_rdy), .dst0_rdy_o(testtx_dst_rdy),
+ .data1_i(testtx_data), .src1_rdy_i(1'b0), .dst1_rdy_o(), // No 2nd input
+ .data0_o(timedtx_data), .src0_rdy_o(timedtx_src_rdy), .dst0_rdy_i(timedtx_dst_rdy),
+ .data1_o(loopbacktx_data), .src1_rdy_o(loopbacktx_src_rdy), .dst1_rdy_i(loopbacktx_dst_rdy) );
+
+ // Fixed rate TX traffic consumer
+ fifo_pacer tx_pacer
+ (.clk(fifo_clk), .reset(fifo_rst), .rate(test_rate), .enable(pkt_sink_enable),
+ .src1_rdy_i(timedtx_src_rdy), .dst1_rdy_o(timedtx_dst_rdy),
+ .src2_rdy_o(timedtx_src_rdy_int), .dst2_rdy_i(timedtx_dst_rdy_int),
+ .underrun(tx_underrun), .overrun());
+
+ packet_verifier32 pktver32
+ (.clk(fifo_clk), .reset(fifo_rst), .clear(clear_tx),
+ .data_i(timedtx_data), .src_rdy_i(timedtx_src_rdy_int), .dst_rdy_o(timedtx_dst_rdy_int),
+ .total(total), .crc_err(crc_err), .seq_err(seq_err), .len_err(len_err));
+
+ // Fixed rate RX traffic generator
+ vita_pkt_gen pktgen
+ (.clk(fifo_clk), .reset(fifo_rst), .clear(clear_rx),
+ .len(test_len),
+ .data_o(timedrx_data), .src_rdy_o(timedrx_src_rdy_int), .dst_rdy_i(timedrx_dst_rdy_int));
+
+ fifo_pacer rx_pacer
+ (.clk(fifo_clk), .reset(fifo_rst), .rate(test_rate), .enable(pkt_src_enable),
+ .src1_rdy_i(timedrx_src_rdy_int), .dst1_rdy_o(timedrx_dst_rdy_int),
+ .src2_rdy_o(timedrx_src_rdy), .dst2_rdy_i(timedrx_dst_rdy),
+ .underrun(), .overrun(rx_overrun));
+*/
+ // ////////////////////////////////////////////
+ // DEBUG
+
+ assign debug0 = { pktend_latch, data_rx_src_rdy, gpif_ctl[3:0], sloe, slrd, slwr, pktend, fifoadr[1:0], state[3:0], gpif_d[15:0]};
+ //assign debug0 = { data_tx_src_rdy, data_tx_dst_rdy, tx_src_rdy_int, tx_dst_rdy_int,
+ // tx19_src_rdy, tx19_dst_rdy, refr_src_rdy, refr_dst_rdy,
+ // tx36_src_rdy, tx36_dst_rdy,
+ // gpif_ctl[3:0], fifoadr[1:0],
+ // wr_fifo_space[15:0]};
+ assign debug1 = { 16'b0, transfer_count[7:0], ctrl_rx_src_rdy, ctrl_tx_dst_rdy, data_rx_src_rdy,
+ data_tx_dst_rdy, ctrl_tx_src_rdy, ctrl_rx_dst_rdy, data_tx_src_rdy, data_rx_dst_rdy};
+endmodule // slave_fifo
diff --git a/fpga/usrp2/sdr_lib/Makefile.srcs b/fpga/usrp2/sdr_lib/Makefile.srcs
index 629b92cc8..e6c4c5343 100644
--- a/fpga/usrp2/sdr_lib/Makefile.srcs
+++ b/fpga/usrp2/sdr_lib/Makefile.srcs
@@ -1,5 +1,5 @@
#
-# Copyright 2010 Ettus Research LLC
+# Copyright 2010-2012 Ettus Research LLC
#
##################################################
@@ -23,9 +23,10 @@ clip_reg.v \
cordic.v \
cordic_z24.v \
cordic_stage.v \
-dsp_core_rx.v \
-dsp_core_tx.v \
+ddc_chain.v \
+duc_chain.v \
dspengine_16to8.v \
+dspengine_8to16.v \
hb_dec.v \
hb_interp.v \
pipectrl.v \
@@ -39,4 +40,6 @@ sign_extend.v \
small_hb_dec.v \
small_hb_int.v \
tx_frontend.v \
+dsp_tx_glue.v \
+dsp_rx_glue.v \
))
diff --git a/fpga/usrp2/sdr_lib/cordic_z24.v b/fpga/usrp2/sdr_lib/cordic_z24.v
index 97b7beaf7..51b074a33 100644
--- a/fpga/usrp2/sdr_lib/cordic_z24.v
+++ b/fpga/usrp2/sdr_lib/cordic_z24.v
@@ -119,8 +119,6 @@ module cordic_z24(clock, reset, enable, xi, yi, zi, xo, yo, zo );
assign xo = x20[bitwidth:1];
assign yo = y20[bitwidth:1];
assign zo = z20;
- //assign xo = x20[bitwidth+1:2]; // CORDIC gain is ~1.6, plus gain from rotating vectors
- //assign yo = y20[bitwidth+1:2];
endmodule // cordic
diff --git a/fpga/usrp2/sdr_lib/ddc_chain.v b/fpga/usrp2/sdr_lib/ddc_chain.v
new file mode 100644
index 000000000..c32c9f491
--- /dev/null
+++ b/fpga/usrp2/sdr_lib/ddc_chain.v
@@ -0,0 +1,190 @@
+//
+// Copyright 2011-2012 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/>.
+//
+
+//! The USRP digital down-conversion chain
+
+module ddc_chain
+ #(
+ parameter BASE = 0,
+ parameter DSPNO = 0,
+ parameter WIDTH = 24
+ )
+ (input clk, input rst, input clr,
+ input set_stb, input [7:0] set_addr, input [31:0] set_data,
+ input set_stb_user, input [7:0] set_addr_user, input [31:0] set_data_user,
+
+ // From RX frontend
+ input [WIDTH-1:0] rx_fe_i,
+ input [WIDTH-1:0] rx_fe_q,
+
+ // To RX control
+ output [31:0] sample,
+ input run,
+ output strobe,
+ output [31:0] debug
+ );
+
+ localparam cwidth = 25;
+ localparam zwidth = 24;
+
+ wire ddc_enb;
+ wire [31:0] phase_inc;
+ reg [31:0] phase;
+
+ wire [17:0] scale_factor;
+ wire [cwidth-1:0] i_cordic, q_cordic;
+ wire [WIDTH-1:0] i_cordic_clip, q_cordic_clip;
+ wire [WIDTH-1:0] i_cic, q_cic;
+ wire [WIDTH-1:0] i_hb1, q_hb1;
+ wire [WIDTH-1:0] i_hb2, q_hb2;
+
+ wire strobe_cic, strobe_hb1, strobe_hb2;
+ wire enable_hb1, enable_hb2;
+ wire [7:0] cic_decim_rate;
+
+ reg [WIDTH-1:0] rx_fe_i_mux, rx_fe_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), .width(18)) sr_1
+ (.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr),
+ .in(set_data),.out(scale_factor),.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());
+
+ setting_reg #(.my_addr(BASE+3), .width(2)) sr_3
+ (.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr),
+ .in(set_data),.out({realmode,swap_iq}),.changed());
+
+ // MUX so we can do realmode signals on either input
+
+ always @(posedge clk)
+ if(swap_iq)
+ begin
+ rx_fe_i_mux <= rx_fe_q;
+ rx_fe_q_mux <= realmode ? 0 : rx_fe_i;
+ end
+ else
+ begin
+ rx_fe_i_mux <= rx_fe_i;
+ rx_fe_q_mux <= realmode ? 0 : rx_fe_q;
+ end
+
+ // NCO
+ always @(posedge clk)
+ if(rst)
+ phase <= 0;
+ else if(~ddc_enb)
+ phase <= 0;
+ else
+ phase <= phase + phase_inc;
+
+ //sign extension of cordic input
+ wire [WIDTH-1:0] to_ddc_chain_i, to_ddc_chain_q;
+ wire [cwidth-1:0] to_cordic_i, to_cordic_q;
+ sign_extend #(.bits_in(WIDTH), .bits_out(cwidth)) sign_extend_cordic_i (.in(to_ddc_chain_i), .out(to_cordic_i));
+ sign_extend #(.bits_in(WIDTH), .bits_out(cwidth)) sign_extend_cordic_q (.in(to_ddc_chain_q), .out(to_cordic_q));
+
+ // CORDIC 24-bit I/O
+ cordic_z24 #(.bitwidth(cwidth))
+ cordic(.clock(clk), .reset(rst), .enable(ddc_enb),
+ .xi(to_cordic_i),. yi(to_cordic_q), .zi(phase[31:32-zwidth]),
+ .xo(i_cordic),.yo(q_cordic),.zo() );
+
+ clip_reg #(.bits_in(cwidth), .bits_out(WIDTH)) clip_i
+ (.clk(clk), .in(i_cordic), .strobe_in(1'b1), .out(i_cordic_clip));
+ clip_reg #(.bits_in(cwidth), .bits_out(WIDTH)) clip_q
+ (.clk(clk), .in(q_cordic), .strobe_in(1'b1), .out(q_cordic_clip));
+
+ // CIC decimator 24 bit I/O
+ cic_strober cic_strober(.clock(clk),.reset(rst),.enable(ddc_enb),.rate(cic_decim_rate),
+ .strobe_fast(1),.strobe_slow(strobe_cic) );
+
+ cic_decim #(.bw(WIDTH))
+ decim_i (.clock(clk),.reset(rst),.enable(ddc_enb),
+ .rate(cic_decim_rate),.strobe_in(1'b1),.strobe_out(strobe_cic),
+ .signal_in(i_cordic_clip),.signal_out(i_cic));
+
+ cic_decim #(.bw(WIDTH))
+ decim_q (.clock(clk),.reset(rst),.enable(ddc_enb),
+ .rate(cic_decim_rate),.strobe_in(1'b1),.strobe_out(strobe_cic),
+ .signal_in(q_cordic_clip),.signal_out(q_cic));
+
+ // First (small) halfband 24 bit I/O
+ small_hb_dec #(.WIDTH(WIDTH)) small_hb_i
+ (.clk(clk),.rst(rst),.bypass(~enable_hb1),.run(ddc_enb),
+ .stb_in(strobe_cic),.data_in(i_cic),.stb_out(strobe_hb1),.data_out(i_hb1));
+
+ small_hb_dec #(.WIDTH(WIDTH)) small_hb_q
+ (.clk(clk),.rst(rst),.bypass(~enable_hb1),.run(ddc_enb),
+ .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 #(.WIDTH(WIDTH)) hb_i
+ (.clk(clk),.rst(rst),.bypass(~enable_hb2),.run(ddc_enb),.cpi(cpi_hb),
+ .stb_in(strobe_hb1),.data_in(i_hb1),.stb_out(strobe_hb2),.data_out(i_hb2));
+
+ hb_dec #(.WIDTH(WIDTH)) hb_q
+ (.clk(clk),.rst(rst),.bypass(~enable_hb2),.run(ddc_enb),.cpi(cpi_hb),
+ .stb_in(strobe_hb1),.data_in(q_hb1),.stb_out(),.data_out(q_hb2));
+
+ //scalar operation (gain of 6 bits)
+ wire [35:0] prod_i, prod_q;
+
+ MULT18X18S mult_i
+ (.P(prod_i), .A(i_hb2[WIDTH-1:WIDTH-18]), .B(scale_factor), .C(clk), .CE(strobe_hb2), .R(rst) );
+ MULT18X18S mult_q
+ (.P(prod_q), .A(q_hb2[WIDTH-1:WIDTH-18]), .B(scale_factor), .C(clk), .CE(strobe_hb2), .R(rst) );
+
+ //pipeline for the multiplier (gain of 10 bits)
+ reg [WIDTH-1:0] prod_reg_i, prod_reg_q;
+ reg strobe_mult;
+
+ always @(posedge clk) begin
+ strobe_mult <= strobe_hb2;
+ prod_reg_i <= prod_i[33:34-WIDTH];
+ prod_reg_q <= prod_q[33:34-WIDTH];
+ end
+
+ // Round final answer to 16 bits
+ wire [31:0] ddc_chain_out;
+ wire ddc_chain_stb;
+
+ round_sd #(.WIDTH_IN(WIDTH),.WIDTH_OUT(16)) round_i
+ (.clk(clk),.reset(rst), .in(prod_reg_i),.strobe_in(strobe_mult), .out(ddc_chain_out[31:16]), .strobe_out(ddc_chain_stb));
+
+ round_sd #(.WIDTH_IN(WIDTH),.WIDTH_OUT(16)) round_q
+ (.clk(clk),.reset(rst), .in(prod_reg_q),.strobe_in(strobe_mult), .out(ddc_chain_out[15:0]), .strobe_out());
+
+ dsp_rx_glue #(.DSPNO(DSPNO), .WIDTH(WIDTH)) custom(
+ .clock(clk), .reset(rst), .clear(clr), .enable(run),
+ .set_stb(set_stb_user), .set_addr(set_addr_user), .set_data(set_data_user),
+ .frontend_i(rx_fe_i_mux), .frontend_q(rx_fe_q_mux),
+ .ddc_in_i(to_ddc_chain_i), .ddc_in_q(to_ddc_chain_q),
+ .ddc_out_sample(ddc_chain_out), .ddc_out_strobe(ddc_chain_stb), .ddc_out_enable(ddc_enb),
+ .bb_sample(sample), .bb_strobe(strobe));
+
+ assign debug = {enable_hb1, enable_hb2, run, strobe, strobe_cic, strobe_hb1, strobe_hb2};
+
+endmodule // ddc_chain
diff --git a/fpga/usrp2/sdr_lib/dsp_core_rx.v b/fpga/usrp2/sdr_lib/dsp_core_rx.v
deleted file mode 100644
index d1c7e238a..000000000
--- a/fpga/usrp2/sdr_lib/dsp_core_rx.v
+++ /dev/null
@@ -1,144 +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/>.
-//
-
-
-module dsp_core_rx
- #(parameter BASE = 160)
- (input clk, input rst,
- input set_stb, input [7:0] set_addr, input [31:0] set_data,
-
- input [23:0] adc_i, input adc_ovf_i,
- input [23:0] adc_q, input adc_ovf_q,
-
- output [31:0] sample,
- input run,
- output strobe,
- output [31:0] debug
- );
-
- wire [31:0] phase_inc;
- reg [31:0] phase;
-
- wire [24:0] i_cordic, q_cordic;
- wire [23:0] i_cordic_clip, q_cordic_clip;
- wire [23:0] i_cic, q_cic;
- 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());
-
- setting_reg #(.my_addr(BASE+3), .width(2)) sr_3
- (.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr),
- .in(set_data),.out({realmode,swap_iq}),.changed());
-
- // MUX so we can do realmode signals on either input
-
- always @(posedge clk)
- 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;
- else if(~run)
- phase <= 0;
- else
- phase <= phase + phase_inc;
-
- // CORDIC 24-bit I/O
- cordic_z24 #(.bitwidth(25))
- cordic(.clock(clk), .reset(rst), .enable(run),
- .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), .strobe_in(1'b1), .out(i_cordic_clip));
- clip_reg #(.bits_in(25), .bits_out(24)) clip_q
- (.clk(clk), .in(q_cordic), .strobe_in(1'b1), .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_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_clip),.signal_out(q_cic));
-
- // 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),.data_in(i_cic),.stb_out(strobe_hb1),.data_out(i_hb1));
-
- small_hb_dec #(.WIDTH(24)) small_hb_q
- (.clk(clk),.rst(rst),.bypass(~enable_hb1),.run(run),
- .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 #(.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 #(.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 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));
-
- 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 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_old.v b/fpga/usrp2/sdr_lib/dsp_core_rx_old.v
deleted file mode 100644
index 90d5d839f..000000000
--- a/fpga/usrp2/sdr_lib/dsp_core_rx_old.v
+++ /dev/null
@@ -1,200 +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/>.
-//
-
-
-`define DSP_CORE_RX_BASE 160
-module dsp_core_rx_old
- (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 [15:0] io_rx,
-
- output [31:0] sample,
- input run,
- output strobe,
- 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 [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 strobe_cic, strobe_hb1, strobe_hb2;
- wire enable_hb1, enable_hb2;
- wire [7:0] cic_decim_rate;
-
- wire [31:10] UNUSED_1;
- wire [31:4] UNUSED_2;
- wire [31:2] UNUSED_3;
-
- setting_reg #(.my_addr(`DSP_CORE_RX_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(`DSP_CORE_RX_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(`DSP_CORE_RX_BASE+2)) sr_2
- (.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr),
- .in(set_data),.out({UNUSED_1, enable_hb1, enable_hb2, cic_decim_rate}),.changed());
-
- rx_dcoffset #(.WIDTH(14),.ADDR(`DSP_CORE_RX_BASE+6)) 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(`DSP_CORE_RX_BASE+7)) 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 [3:0] muxctrl;
- setting_reg #(.my_addr(`DSP_CORE_RX_BASE+8)) sr_8
- (.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr),
- .in(set_data),.out({UNUSED_2,muxctrl}),.changed());
-
- wire [1:0] gpio_ena;
- setting_reg #(.my_addr(`DSP_CORE_RX_BASE+9)) sr_9
- (.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr),
- .in(set_data),.out({UNUSED_3,gpio_ena}),.changed());
-
- // The TVRX connects to what is called adc_b, thus A and B are
- // swapped throughout the design.
- //
- // In the interest of expediency and keeping the s/w sane, we just remap them here.
- // The I & Q fields are mapped the same:
- // 0 -> "the real A" (as determined by the TVRX)
- // 1 -> "the real B"
- // 2 -> const zero
-
- always @(posedge clk)
- case(muxctrl[1:0]) // The I mapping
- 0: adc_i <= adc_b_ofs; // "the real A"
- 1: adc_i <= adc_a_ofs;
- 2: adc_i <= 0;
- default: adc_i <= 0;
- endcase // case(muxctrl[1:0])
-
- always @(posedge clk)
- case(muxctrl[3:2]) // The Q mapping
- 0: adc_q <= adc_b_ofs; // "the real A"
- 1: adc_q <= adc_a_ofs;
- 2: adc_q <= 0;
- default: adc_q <= 0;
- endcase // case(muxctrl[3:2])
-
- always @(posedge clk)
- if(rst)
- phase <= 0;
- else if(~run)
- phase <= 0;
- 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(.clock(clk), .reset(rst), .enable(run),
- .xi(prod_i[23:0]),. yi(prod_q[23:0]), .zi(phase[31:8]),
- .xo(i_cordic),.yo(q_cordic),.zo() );
-
- 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));
-
- 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));
-
- 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
- (.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));
-
- small_hb_dec #(.WIDTH(18)) 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));
-
- 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
- (.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
- (.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));
-
- // Streaming GPIO
- //
- // io_rx[15] => I channel LSB if gpio_ena[0] high
- // io_rx[14] => Q channel LSB if gpio_ena[1] high
-
- reg [31:0] sample_reg;
- always @(posedge clk)
- begin
- sample_reg[31:17] <= i_out[15:1];
- sample_reg[15:1] <= q_out[15:1];
- sample_reg[16] <= gpio_ena[0] ? io_rx[15] : i_out[0];
- sample_reg[0] <= gpio_ena[1] ? io_rx[14] : q_out[0];
- end
-
- 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};
-
-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
index 271db8cef..a221bed44 100644
--- a/fpga/usrp2/sdr_lib/dsp_core_rx_tb.v
+++ b/fpga/usrp2/sdr_lib/dsp_core_rx_tb.v
@@ -1,6 +1,6 @@
`timescale 1ns/1ns
-module dsp_core_rx_tb();
+module ddc_chain_tb();
reg clk, rst;
@@ -9,8 +9,8 @@ module dsp_core_rx_tb();
initial clk = 0;
always #5 clk = ~clk;
- initial $dumpfile("dsp_core_rx_tb.vcd");
- initial $dumpvars(0,dsp_core_rx_tb);
+ initial $dumpfile("ddc_chain_tb.vcd");
+ initial $dumpvars(0,ddc_chain_tb);
reg signed [23:0] adc_in;
wire signed [15:0] adc_out_i, adc_out_q;
@@ -27,7 +27,7 @@ module dsp_core_rx_tb();
reg [7:0] set_addr;
reg [31:0] set_data;
- dsp_core_rx #(.BASE(0)) dsp_core_rx
+ ddc_chain #(.BASE(0)) ddc_chain
(.clk(clk),.rst(rst),
.set_stb(set_stb),.set_addr(set_addr),.set_data(set_data),
.adc_i(adc_in), .adc_ovf_i(0),
@@ -70,4 +70,4 @@ module dsp_core_rx_tb();
adc_in <= adc_in + 4;
//adc_in <= (($random % 473) + 23)/4;
*/
-endmodule // dsp_core_rx_tb
+endmodule // ddc_chain_tb
diff --git a/fpga/usrp2/sdr_lib/dsp_core_rx_udp.v b/fpga/usrp2/sdr_lib/dsp_core_rx_udp.v
deleted file mode 100644
index 08dab37e6..000000000
--- a/fpga/usrp2/sdr_lib/dsp_core_rx_udp.v
+++ /dev/null
@@ -1,200 +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/>.
-//
-
-
-module dsp_core_rx
- #(parameter BASE = 160)
- (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 [15:0] io_rx,
-
- output [31:0] sample,
- input run,
- output strobe,
- 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 [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 strobe_cic, strobe_hb1, strobe_hb2;
- wire enable_hb1, enable_hb2;
- wire [7:0] cic_decim_rate;
-
- wire [31:10] UNUSED_1;
- wire [31:4] UNUSED_2;
- wire [31:2] UNUSED_3;
-
- 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)) sr_2
- (.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr),
- .in(set_data),.out({UNUSED_1, 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 [3:0] muxctrl;
- setting_reg #(.my_addr(BASE+5)) sr_8
- (.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr),
- .in(set_data),.out({UNUSED_2,muxctrl}),.changed());
-
- wire [1:0] gpio_ena;
- setting_reg #(.my_addr(BASE+6)) sr_9
- (.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr),
- .in(set_data),.out({UNUSED_3,gpio_ena}),.changed());
-
- // The TVRX connects to what is called adc_b, thus A and B are
- // swapped throughout the design.
- //
- // In the interest of expediency and keeping the s/w sane, we just remap them here.
- // The I & Q fields are mapped the same:
- // 0 -> "the real A" (as determined by the TVRX)
- // 1 -> "the real B"
- // 2 -> const zero
-
- always @(posedge clk)
- case(muxctrl[1:0]) // The I mapping
- 0: adc_i <= adc_b_ofs; // "the real A"
- 1: adc_i <= adc_a_ofs;
- 2: adc_i <= 0;
- default: adc_i <= 0;
- endcase // case(muxctrl[1:0])
-
- always @(posedge clk)
- case(muxctrl[3:2]) // The Q mapping
- 0: adc_q <= adc_b_ofs; // "the real A"
- 1: adc_q <= adc_a_ofs;
- 2: adc_q <= 0;
- default: adc_q <= 0;
- endcase // case(muxctrl[3:2])
-
- always @(posedge clk)
- if(rst)
- phase <= 0;
- else if(~run)
- phase <= 0;
- 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(.clock(clk), .reset(rst), .enable(run),
- .xi(prod_i[23:0]),. yi(prod_q[23:0]), .zi(phase[31:8]),
- .xo(i_cordic),.yo(q_cordic),.zo() );
-
- 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));
-
- 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));
-
- 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
- (.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));
-
- small_hb_dec #(.WIDTH(18)) 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));
-
- 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
- (.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
- (.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));
-
- // Streaming GPIO
- //
- // io_rx[15] => I channel LSB if gpio_ena[0] high
- // io_rx[14] => Q channel LSB if gpio_ena[1] high
-
- reg [31:0] sample_reg;
- always @(posedge clk)
- begin
- sample_reg[31:17] <= i_out[15:1];
- sample_reg[15:1] <= q_out[15:1];
- sample_reg[16] <= gpio_ena[0] ? io_rx[15] : i_out[0];
- sample_reg[0] <= gpio_ena[1] ? io_rx[14] : q_out[0];
- end
-
- 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};
-
-endmodule // dsp_core_rx
diff --git a/fpga/usrp2/sdr_lib/dsp_rx_glue.v b/fpga/usrp2/sdr_lib/dsp_rx_glue.v
new file mode 100644
index 000000000..038a67a29
--- /dev/null
+++ b/fpga/usrp2/sdr_lib/dsp_rx_glue.v
@@ -0,0 +1,98 @@
+//
+// Copyright 2012 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/>.
+//
+
+//The following module effects the IO of the DDC chain.
+//By default, this entire module is a simple pass-through.
+
+module dsp_rx_glue
+#(
+ //the dsp unit number: 0, 1, 2...
+ parameter DSPNO = 0,
+
+ //frontend bus width
+ parameter WIDTH = 24
+)
+(
+ //control signals
+ input clock, input reset, input clear, input enable,
+
+ //user settings bus, controlled through user setting regs API
+ input set_stb, input [7:0] set_addr, input [31:0] set_data,
+
+ //full rate inputs directly from the RX frontend
+ input [WIDTH-1:0] frontend_i,
+ input [WIDTH-1:0] frontend_q,
+
+ //full rate outputs directly to the DDC chain
+ output [WIDTH-1:0] ddc_in_i,
+ output [WIDTH-1:0] ddc_in_q,
+
+ //strobed samples {I16,Q16} from the RX DDC chain
+ input [31:0] ddc_out_sample,
+ input ddc_out_strobe, //high on valid sample
+ output ddc_out_enable, //enables DDC module
+
+ //strobbed baseband samples {I16,Q16} from this module
+ output [31:0] bb_sample,
+ output bb_strobe, //high on valid sample
+
+ //debug output (optional)
+ output [31:0] debug
+);
+
+ generate
+ if (DSPNO==0) begin
+ `ifndef RX_DSP0_MODULE
+ assign ddc_in_i = frontend_i;
+ assign ddc_in_q = frontend_q;
+ assign bb_sample = ddc_out_sample;
+ assign bb_strobe = ddc_out_strobe;
+ assign ddc_out_enable = enable;
+ `else
+ `RX_DSP0_MODULE #(.WIDTH(WIDTH)) rx_dsp0_custom
+ (
+ .clock(clock), .reset(reset), .clear(clear), .enable(enable),
+ .set_stb(set_stb), .set_addr(set_addr), .set_data(set_data),
+ .frontend_i(frontend_i), .frontend_q(frontend_q),
+ .ddc_in_i(ddc_in_i), .ddc_in_q(ddc_in_q),
+ .ddc_out_sample(ddc_out_sample), .ddc_out_strobe(ddc_out_strobe), .ddc_out_enable(ddc_out_enable),
+ .bb_sample(bb_sample), .bb_strobe(bb_strobe)
+ );
+ `endif
+ end
+ else begin
+ `ifndef RX_DSP1_MODULE
+ assign ddc_in_i = frontend_i;
+ assign ddc_in_q = frontend_q;
+ assign bb_sample = ddc_out_sample;
+ assign bb_strobe = ddc_out_strobe;
+ assign ddc_out_enable = enable;
+ `else
+ `RX_DSP1_MODULE #(.WIDTH(WIDTH)) rx_dsp1_custom
+ (
+ .clock(clock), .reset(reset), .clear(clear), .enable(enable),
+ .set_stb(set_stb), .set_addr(set_addr), .set_data(set_data),
+ .frontend_i(frontend_i), .frontend_q(frontend_q),
+ .ddc_in_i(ddc_in_i), .ddc_in_q(ddc_in_q),
+ .ddc_out_sample(ddc_out_sample), .ddc_out_strobe(ddc_out_strobe), .ddc_out_enable(ddc_out_enable),
+ .bb_sample(bb_sample), .bb_strobe(bb_strobe)
+ );
+ `endif
+ end
+ endgenerate
+
+endmodule //dsp_rx_glue
diff --git a/fpga/usrp2/sdr_lib/dsp_tx_glue.v b/fpga/usrp2/sdr_lib/dsp_tx_glue.v
new file mode 100644
index 000000000..46f6789ee
--- /dev/null
+++ b/fpga/usrp2/sdr_lib/dsp_tx_glue.v
@@ -0,0 +1,98 @@
+//
+// Copyright 2012 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/>.
+//
+
+//The following module effects the IO of the DUC chain.
+//By default, this entire module is a simple pass-through.
+
+module dsp_tx_glue
+#(
+ //the dsp unit number: 0, 1, 2...
+ parameter DSPNO = 0,
+
+ //frontend bus width
+ parameter WIDTH = 24
+)
+(
+ //control signals
+ input clock, input reset, input clear, input enable,
+
+ //user settings bus, controlled through user setting regs API
+ input set_stb, input [7:0] set_addr, input [31:0] set_data,
+
+ //full rate outputs directly to the TX frontend
+ output [WIDTH-1:0] frontend_i,
+ output [WIDTH-1:0] frontend_q,
+
+ //full rate outputs directly from the DUC chain
+ input [WIDTH-1:0] duc_out_i,
+ input [WIDTH-1:0] duc_out_q,
+
+ //strobed samples {I16,Q16} to the TX DUC chain
+ output [31:0] duc_in_sample,
+ input duc_in_strobe, //this is a backpressure signal
+ output duc_in_enable, //enables DUC module
+
+ //strobbed baseband samples {I16,Q16} to this module
+ input [31:0] bb_sample,
+ output bb_strobe, //this is a backpressure signal
+
+ //debug output (optional)
+ output [31:0] debug
+);
+
+ generate
+ if (DSPNO==0) begin
+ `ifndef TX_DSP0_MODULE
+ assign frontend_i = duc_out_i;
+ assign frontend_q = duc_out_q;
+ assign duc_in_sample = bb_sample;
+ assign bb_strobe = duc_in_strobe;
+ assign duc_in_enable = enable;
+ `else
+ `TX_DSP0_MODULE #(.WIDTH(WIDTH)) tx_dsp0_custom
+ (
+ .clock(clock), .reset(reset), .clear(clear), .enable(enable),
+ .set_stb(set_stb), .set_addr(set_addr), .set_data(set_data),
+ .frontend_i(frontend_i), .frontend_q(frontend_q),
+ .duc_out_i(duc_out_i), .duc_out_q(duc_out_q),
+ .duc_in_sample(duc_in_sample), .duc_in_strobe(duc_in_strobe), .duc_in_enable(duc_in_enable),
+ .bb_sample(bb_sample), .bb_strobe(bb_strobe)
+ );
+ `endif
+ end
+ else begin
+ `ifndef TX_DSP1_MODULE
+ assign frontend_i = duc_out_i;
+ assign frontend_q = duc_out_q;
+ assign duc_in_sample = bb_sample;
+ assign bb_strobe = duc_in_strobe;
+ assign duc_in_enable = enable;
+ `else
+ `TX_DSP1_MODULE #(.WIDTH(WIDTH)) tx_dsp1_custom
+ (
+ .clock(clock), .reset(reset), .clear(clear), .enable(enable),
+ .set_stb(set_stb), .set_addr(set_addr), .set_data(set_data),
+ .frontend_i(frontend_i), .frontend_q(frontend_q),
+ .duc_out_i(duc_out_i), .duc_out_q(duc_out_q),
+ .duc_in_sample(duc_in_sample), .duc_in_strobe(duc_in_strobe), .duc_in_enable(duc_in_enable),
+ .bb_sample(bb_sample), .bb_strobe(bb_strobe)
+ );
+ `endif
+ end
+ endgenerate
+
+endmodule //dsp_tx_glue
diff --git a/fpga/usrp2/sdr_lib/dspengine_16to8.v b/fpga/usrp2/sdr_lib/dspengine_16to8.v
index 53c5d29da..448c57d35 100644
--- a/fpga/usrp2/sdr_lib/dspengine_16to8.v
+++ b/fpga/usrp2/sdr_lib/dspengine_16to8.v
@@ -1,5 +1,5 @@
-// Copyright 2011 Ettus Research LLC
+// Copyright 2011-2012 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
@@ -32,13 +32,11 @@ module dspengine_16to8
input [35:0] access_dat_i
);
- wire convert;
- wire [17:0] scale_factor;
-
- setting_reg #(.my_addr(BASE),.width(19)) sr_16to8
+ wire convert;
+ setting_reg #(.my_addr(BASE),.width(1)) sr_16to8
(.clk(clk),.rst(reset),.strobe(set_stb),.addr(set_addr),
- .in(set_data),.out({convert,scale_factor}),.changed());
-
+ .in(set_data),.out(convert),.changed());
+
reg [2:0] dsp_state;
localparam DSP_IDLE = 0;
localparam DSP_PARSE_HEADER = 1;
@@ -63,7 +61,7 @@ module dspengine_16to8
wire [15:0] scaled_i, scaled_q;
wire [7:0] i8, q8;
reg [7:0] i8_reg, q8_reg;
- wire stb_read, stb_mult, stb_clip, stb_round, val_read, val_mult, val_clip, val_round;
+ wire stb_read, stb_clip, val_read, val_clip;
wire stb_out, stb_reg;
reg even;
@@ -193,29 +191,21 @@ module dspengine_16to8
wire [15:0] i16 = access_dat_i[31:16];
wire [15:0] q16 = access_dat_i[15:0];
- pipectrl #(.STAGES(4), .TAGWIDTH(2)) pipectrl
+ pipectrl #(.STAGES(2), .TAGWIDTH(2)) pipectrl
(.clk(clk), .reset(reset),
.src_rdy_i(send_to_pipe), .dst_rdy_o(), // dst_rdy_o will always be 1 since dst_rdy_i is 1, below
.src_rdy_o(stb_out), .dst_rdy_i(1), // always accept output of chain
- .strobes({stb_round,stb_clip,stb_mult,stb_read}), .valids({val_round,val_clip,val_mult,val_read}),
+ .strobes({stb_clip,stb_read}), .valids({val_clip,val_read}),
.tag_i({last,even}), .tag_o({last_o,even_o}));
always @(posedge clk)
if(stb_out & ~even_o)
{i8_reg,q8_reg} <= {i8,q8};
-
- MULT18X18S mult_i
- (.P(prod_i), .A(scale_factor), .B({i16,2'b00}), .C(clk), .CE(stb_mult), .R(reset) );
- clip_reg #(.bits_in(24),.bits_out(16),.STROBED(1)) clip_i
- (.clk(clk), .in(prod_i[35:12]), .out(scaled_i), .strobe_in(stb_clip), .strobe_out());
- round_sd #(.WIDTH_IN(16),.WIDTH_OUT(8),.DISABLE_SD(1)) round_i
- (.clk(clk), .reset(reset), .in(scaled_i), .strobe_in(stb_round), .out(i8), .strobe_out());
-
- MULT18X18S mult_q
- (.P(prod_q), .A(scale_factor), .B({q16,2'b00}), .C(clk), .CE(stb_mult), .R(reset) );
- clip_reg #(.bits_in(24),.bits_out(16),.STROBED(1)) clip_q
- (.clk(clk), .in(prod_q[35:12]), .out(scaled_q), .strobe_in(stb_clip), .strobe_out());
- round_sd #(.WIDTH_IN(16),.WIDTH_OUT(8),.DISABLE_SD(1)) round_q
- (.clk(clk), .reset(reset), .in(scaled_q), .strobe_in(stb_round), .out(q8), .strobe_out());
+
+ clip_reg #(.bits_in(16),.bits_out(8),.STROBED(1)) clip_i
+ (.clk(clk), .in(i16), .out(i8), .strobe_in(stb_clip), .strobe_out());
+
+ clip_reg #(.bits_in(16),.bits_out(8),.STROBED(1)) clip_q
+ (.clk(clk), .in(q16), .out(q8), .strobe_in(stb_clip), .strobe_out());
endmodule // dspengine_16to8
diff --git a/fpga/usrp2/sdr_lib/dspengine_8to16.v b/fpga/usrp2/sdr_lib/dspengine_8to16.v
new file mode 100644
index 000000000..85187d78d
--- /dev/null
+++ b/fpga/usrp2/sdr_lib/dspengine_8to16.v
@@ -0,0 +1,203 @@
+
+// Copyright 2012 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 dspengine_8to16
+ #(parameter BASE = 0,
+ parameter BUF_SIZE = 9,
+ parameter HEADER_OFFSET = 0)
+ (input clk, input reset, input clear,
+ input set_stb, input [7:0] set_addr, input [31:0] set_data,
+
+ output access_we,
+ output access_stb,
+ input access_ok,
+ output access_done,
+ output access_skip_read,
+ output [BUF_SIZE-1:0] access_adr,
+ input [BUF_SIZE-1:0] access_len,
+ output [35:0] access_dat_o,
+ input [35:0] access_dat_i
+ );
+
+ wire convert;
+
+ setting_reg #(.my_addr(BASE),.width(1)) sr_8to16
+ (.clk(clk),.rst(reset),.strobe(set_stb),.addr(set_addr),
+ .in(set_data),.out(convert),.changed());
+
+ reg [3:0] dsp_state;
+ localparam DSP_IDLE = 0;
+ localparam DSP_IDLE_RD = 1;
+ localparam DSP_PARSE_HEADER = 2;
+ localparam DSP_READ = 3;
+ localparam DSP_READ_WAIT = 4;
+ localparam DSP_WRITE_1 = 5;
+ localparam DSP_WRITE_0 = 6;
+ localparam DSP_READ_TRAILER = 7;
+ localparam DSP_WRITE_TRAILER = 8;
+ localparam DSP_WRITE_HEADER = 9;
+ localparam DSP_DONE = 10;
+
+ // Parse VITA header
+ wire is_if_data = (access_dat_i[31:29] == 3'b000);
+ wire has_streamid = access_dat_i[28];
+ wire has_classid = access_dat_i[27];
+ wire has_trailer = access_dat_i[26];
+ // 25:24 reserved, aka SOB/EOB
+ wire has_secs = |access_dat_i[23:22];
+ wire has_tics = |access_dat_i[21:20];
+ wire [3:0] hdr_length = 1 + has_streamid + has_classid + has_classid + has_secs + has_tics + has_tics;
+ reg [15:0] hdr_length_reg;
+
+ reg odd;
+
+ reg [BUF_SIZE-1:0] read_adr, write_adr;
+ reg has_trailer_reg;
+
+ reg [31:0] new_header, new_trailer, trailer_mask;
+ reg wait_for_trailer;
+ reg [15:0] data_in_len;
+ wire is_odd = access_dat_i[22] & access_dat_i[10];
+ wire [15:0] data_in_lenx2 = {data_in_len[14:0], 1'b0} - is_odd;
+
+ reg [7:0] i8_0, q8_0;
+ wire [7:0] i8_1 = access_dat_i[31:24];
+ wire [7:0] q8_1 = access_dat_i[23:16];
+ reg skip;
+
+
+ always @(posedge clk)
+ { i8_0, q8_0 } <= access_dat_i[15:0];
+
+ always @(posedge clk)
+ if(reset | clear)
+ dsp_state <= DSP_IDLE;
+ else
+ case(dsp_state)
+ DSP_IDLE :
+ begin
+ read_adr <= HEADER_OFFSET;
+ write_adr <= HEADER_OFFSET;
+ if(access_ok)
+ dsp_state <= DSP_IDLE_RD;
+ end
+
+ DSP_IDLE_RD: //extra idle state for read to become valid
+ dsp_state <= DSP_PARSE_HEADER;
+
+ DSP_PARSE_HEADER :
+ begin
+ has_trailer_reg <= has_trailer;
+ new_header[31:0] <= access_dat_i[31:0];
+ hdr_length_reg <= hdr_length;
+ if(~is_if_data | ~convert | ~has_trailer)
+ // ~convert is valid (16 bit mode) but both ~trailer and ~is_if_data are both
+ // really error conditions on the TX side. We shouldn't ever see them in the TX chain
+ dsp_state <= DSP_WRITE_HEADER;
+ else
+ begin
+ read_adr <= access_dat_i[15:0] + HEADER_OFFSET - 1; // point to trailer
+ dsp_state <= DSP_READ_TRAILER;
+ wait_for_trailer <= 0;
+ data_in_len <= access_dat_i[15:0] - hdr_length - 1 /*trailer*/;
+ end
+ end
+
+ DSP_READ_TRAILER :
+ begin
+ wait_for_trailer <= 1;
+ if(wait_for_trailer)
+ dsp_state <= DSP_WRITE_TRAILER;
+ new_trailer <= access_dat_i[31:0]; // Leave trailer unchanged
+ odd <= is_odd;
+ write_adr <= hdr_length_reg + data_in_lenx2 + HEADER_OFFSET;
+ end
+
+ DSP_WRITE_TRAILER :
+ begin
+ dsp_state <= DSP_READ;
+ write_adr <= write_adr - 1;
+ read_adr <= read_adr - 1;
+ new_header[15:0] <= write_adr + (1 - HEADER_OFFSET); // length = addr of trailer + 1
+ end
+
+ DSP_READ :
+ begin
+ read_adr <= read_adr - 1;
+ if(odd)
+ dsp_state <= DSP_READ_WAIT;
+ else
+ dsp_state <= DSP_WRITE_1;
+ odd <= 0;
+ end
+
+ DSP_READ_WAIT :
+ dsp_state <= DSP_WRITE_0;
+
+ DSP_WRITE_1 :
+ begin
+ write_adr <= write_adr - 1;
+ if(write_adr == (hdr_length_reg+HEADER_OFFSET))
+ begin
+ write_adr <= HEADER_OFFSET;
+ dsp_state <= DSP_WRITE_HEADER;
+ end
+ dsp_state <= DSP_WRITE_0;
+ end
+
+ DSP_WRITE_0 :
+ begin
+ write_adr <= write_adr - 1;
+ if(write_adr == (hdr_length_reg+HEADER_OFFSET))
+ begin
+ write_adr <= HEADER_OFFSET;
+ dsp_state <= DSP_WRITE_HEADER;
+ end
+ else
+ dsp_state <= DSP_READ;
+ end
+
+ DSP_WRITE_HEADER :
+ dsp_state <= DSP_DONE;
+
+ DSP_DONE :
+ begin
+ read_adr <= HEADER_OFFSET;
+ write_adr <= HEADER_OFFSET;
+ dsp_state <= DSP_IDLE;
+ end
+ endcase // case (dsp_state)
+
+ assign access_skip_read = 0;
+ assign access_done = (dsp_state == DSP_DONE);
+
+ assign access_stb = 1;
+
+ assign access_we = (dsp_state == DSP_WRITE_HEADER) |
+ (dsp_state == DSP_WRITE_TRAILER) |
+ (dsp_state == DSP_WRITE_0) |
+ (dsp_state == DSP_WRITE_1);
+
+ assign access_dat_o = (dsp_state == DSP_WRITE_HEADER) ? { 4'h0, new_header } :
+ (dsp_state == DSP_WRITE_TRAILER) ? { 4'h2, new_trailer } :
+ (dsp_state == DSP_WRITE_0) ? { 4'h0, i8_0, 8'd0, q8_0, 8'd0 } :
+ (dsp_state == DSP_WRITE_1) ? { 4'h0, i8_1, 8'd0, q8_1, 8'd0 } :
+ 34'h0DEADBEEF;
+
+ assign access_adr = access_we ? write_adr : read_adr;
+
+endmodule // dspengine_16to8
diff --git a/fpga/usrp2/sdr_lib/dsp_core_tx.v b/fpga/usrp2/sdr_lib/duc_chain.v
index 4e0163e0a..bd3402a1f 100644
--- a/fpga/usrp2/sdr_lib/dsp_core_tx.v
+++ b/fpga/usrp2/sdr_lib/duc_chain.v
@@ -1,5 +1,5 @@
//
-// Copyright 2011 Ettus Research LLC
+// Copyright 2011-2012 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,26 +15,35 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
+//! The USRP digital up-conversion chain
-module dsp_core_tx
- #(parameter BASE=0)
- (input clk, input rst,
+module duc_chain
+ #(
+ parameter BASE = 0,
+ parameter DSPNO = 0,
+ parameter WIDTH = 24
+ )
+ (input clk, input rst, input clr,
input set_stb, input [7:0] set_addr, input [31:0] set_data,
+ input set_stb_user, input [7:0] set_addr_user, input [31:0] set_data_user,
- output [23:0] tx_i, output [23:0] tx_q,
+ // To TX frontend
+ output [WIDTH-1:0] tx_fe_i,
+ output [WIDTH-1:0] tx_fe_q,
- // To tx_control
+ // From TX control
input [31:0] sample,
input run,
output strobe,
output [31:0] debug
);
- wire [15:0] i, q, scale_i, scale_q;
+ wire duc_enb;
+ wire [17:0] scale_factor;
wire [31:0] phase_inc;
reg [31:0] phase;
wire [7:0] interp_rate;
- wire [3:0] dacmux_a, dacmux_b;
+ wire [3:0] tx_femux_a, tx_femux_b;
wire enable_hb1, enable_hb2;
wire rate_change;
@@ -42,9 +51,9 @@ module dsp_core_tx
(.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
+ setting_reg #(.my_addr(BASE+1), .width(18)) sr_1
(.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr),
- .in(set_data),.out({scale_i,scale_q}),.changed());
+ .in(set_data),.out(scale_factor),.changed());
setting_reg #(.my_addr(BASE+2), .width(10)) sr_2
(.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr),
@@ -57,13 +66,13 @@ module dsp_core_tx
reg strobe_hb2 = 1;
cic_strober #(.WIDTH(8))
- cic_strober(.clock(clk),.reset(rst),.enable(run & ~rate_change),.rate(interp_rate),
+ cic_strober(.clock(clk),.reset(rst),.enable(duc_enb & ~rate_change),.rate(interp_rate),
.strobe_fast(1),.strobe_slow(strobe_cic_pre) );
cic_strober #(.WIDTH(2))
- hb2_strober(.clock(clk),.reset(rst),.enable(run & ~rate_change),.rate(enable_hb2 ? 2 : 1),
+ hb2_strober(.clock(clk),.reset(rst),.enable(duc_enb & ~rate_change),.rate(enable_hb2 ? 2 : 1),
.strobe_fast(strobe_cic_pre),.strobe_slow(strobe_hb2_pre) );
cic_strober #(.WIDTH(2))
- hb1_strober(.clock(clk),.reset(rst),.enable(run & ~rate_change),.rate(enable_hb1 ? 2 : 1),
+ hb1_strober(.clock(clk),.reset(rst),.enable(duc_enb & ~rate_change),.rate(enable_hb1 ? 2 : 1),
.strobe_fast(strobe_hb2_pre),.strobe_slow(strobe_hb1_pre) );
always @(posedge clk) strobe_hb1 <= strobe_hb1_pre;
@@ -74,7 +83,7 @@ module dsp_core_tx
always @(posedge clk)
if(rst)
phase <= 0;
- else if(~run)
+ else if(~duc_enb)
phase <= 0;
else
phase <= phase + phase_inc;
@@ -82,8 +91,8 @@ module dsp_core_tx
wire signed [17:0] da, db;
wire signed [35:0] prod_i, prod_q;
- wire [17:0] bb_i = {sample[31:16],2'b0};
- wire [17:0] bb_q = {sample[15:0],2'b0};
+ wire [15:0] bb_i;
+ wire [15:0] bb_q;
wire [17:0] i_interp, q_interp;
wire [17:0] hb1_i, hb1_q, hb2_i, hb2_q;
@@ -92,10 +101,10 @@ module dsp_core_tx
// Note that max CIC rate is 128, which would give an overflow on cpo if enable_hb2 is true,
// but the default case inside hb_interp handles this
- hb_interp #(.IWIDTH(18),.OWIDTH(18),.ACCWIDTH(24)) hb_interp_i
- (.clk(clk),.rst(rst),.bypass(~enable_hb1),.cpo(cpo),.stb_in(strobe_hb1),.data_in(bb_i),.stb_out(strobe_hb2),.data_out(hb1_i));
- hb_interp #(.IWIDTH(18),.OWIDTH(18),.ACCWIDTH(24)) hb_interp_q
- (.clk(clk),.rst(rst),.bypass(~enable_hb1),.cpo(cpo),.stb_in(strobe_hb1),.data_in(bb_q),.stb_out(strobe_hb2),.data_out(hb1_q));
+ hb_interp #(.IWIDTH(18),.OWIDTH(18),.ACCWIDTH(WIDTH)) hb_interp_i
+ (.clk(clk),.rst(rst),.bypass(~enable_hb1),.cpo(cpo),.stb_in(strobe_hb1),.data_in({bb_i, 2'b0}),.stb_out(strobe_hb2),.data_out(hb1_i));
+ hb_interp #(.IWIDTH(18),.OWIDTH(18),.ACCWIDTH(WIDTH)) hb_interp_q
+ (.clk(clk),.rst(rst),.bypass(~enable_hb1),.cpo(cpo),.stb_in(strobe_hb1),.data_in({bb_q, 2'b0}),.stb_out(strobe_hb2),.data_out(hb1_q));
small_hb_int #(.WIDTH(18)) small_hb_interp_i
(.clk(clk),.rst(rst),.bypass(~enable_hb2),.stb_in(strobe_hb2),.data_in(hb1_i),
@@ -105,24 +114,22 @@ module dsp_core_tx
.output_rate(interp_rate),.stb_out(strobe_cic),.data_out(hb2_q));
cic_interp #(.bw(18),.N(4),.log2_of_max_rate(7))
- cic_interp_i(.clock(clk),.reset(rst),.enable(run & ~rate_change),.rate(interp_rate),
+ cic_interp_i(.clock(clk),.reset(rst),.enable(duc_enb & ~rate_change),.rate(interp_rate),
.strobe_in(strobe_cic),.strobe_out(1),
.signal_in(hb2_i),.signal_out(i_interp));
cic_interp #(.bw(18),.N(4),.log2_of_max_rate(7))
- cic_interp_q(.clock(clk),.reset(rst),.enable(run & ~rate_change),.rate(interp_rate),
+ cic_interp_q(.clock(clk),.reset(rst),.enable(duc_enb & ~rate_change),.rate(interp_rate),
.strobe_in(strobe_cic),.strobe_out(1),
.signal_in(hb2_q),.signal_out(q_interp));
- assign strobe = strobe_hb1;
-
- localparam cwidth = 24; // was 18
+ localparam cwidth = WIDTH; // was 18
localparam zwidth = 24; // was 16
wire [cwidth-1:0] da_c, db_c;
cordic_z24 #(.bitwidth(cwidth))
- cordic(.clock(clk), .reset(rst), .enable(run),
+ cordic(.clock(clk), .reset(rst), .enable(duc_enb),
.xi({i_interp,{(cwidth-18){1'b0}}}),.yi({q_interp,{(cwidth-18){1'b0}}}),
.zi(phase[31:32-zwidth]),
.xo(da_c),.yo(db_c),.zo() );
@@ -130,7 +137,7 @@ module dsp_core_tx
MULT18X18S MULT18X18S_inst
(.P(prod_i), // 36-bit multiplier output
.A(da_c[cwidth-1:cwidth-18]), // 18-bit multiplier input
- .B({{2{scale_i[15]}},scale_i}), // 18-bit multiplier input
+ .B(scale_factor), // 18-bit multiplier input
.C(clk), // Clock input
.CE(1), // Clock enable input
.R(rst) // Synchronous reset input
@@ -139,15 +146,20 @@ module dsp_core_tx
MULT18X18S MULT18X18S_inst_2
(.P(prod_q), // 36-bit multiplier output
.A(db_c[cwidth-1:cwidth-18]), // 18-bit multiplier input
- .B({{2{scale_q[15]}},scale_q}), // 18-bit multiplier input
+ .B(scale_factor), // 18-bit multiplier input
.C(clk), // Clock input
.CE(1), // Clock enable input
.R(rst) // Synchronous reset input
);
- assign tx_i = prod_i[28:5];
- assign tx_q = prod_q[28:5];
-
+ dsp_tx_glue #(.DSPNO(DSPNO), .WIDTH(WIDTH)) dsp_tx_glue(
+ .clock(clk), .reset(rst), .clear(clr), .enable(run),
+ .set_stb(set_stb_user), .set_addr(set_addr_user), .set_data(set_data_user),
+ .frontend_i(tx_fe_i), .frontend_q(tx_fe_q),
+ .duc_out_i(prod_i[33:34-WIDTH]), .duc_out_q(prod_q[33:34-WIDTH]),
+ .duc_in_sample({bb_i, bb_q}), .duc_in_strobe(strobe_hb1), .duc_in_enable(duc_enb),
+ .bb_sample(sample), .bb_strobe(strobe));
+
assign debug = {strobe_cic, strobe_hb1, strobe_hb2,run};
endmodule // dsp_core
diff --git a/fpga/usrp2/sdr_lib/dummy_rx.v b/fpga/usrp2/sdr_lib/dummy_rx.v
index b22d5f896..42bbe36b2 100644
--- a/fpga/usrp2/sdr_lib/dummy_rx.v
+++ b/fpga/usrp2/sdr_lib/dummy_rx.v
@@ -76,4 +76,4 @@ module dummy_rx
q_out <= q_out + 1;
-endmodule // dsp_core_rx
+endmodule // ddc_chain
diff --git a/fpga/usrp2/timing/time_64bit.v b/fpga/usrp2/timing/time_64bit.v
index 03df07108..6f335890e 100644
--- a/fpga/usrp2/timing/time_64bit.v
+++ b/fpga/usrp2/timing/time_64bit.v
@@ -1,5 +1,5 @@
//
-// Copyright 2011 Ettus Research LLC
+// Copyright 2011-2012 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 @@
module time_64bit
- #(parameter TICKS_PER_SEC = 32'd100000000,
+ #(
parameter BASE = 0)
(input clk, input rst,
input set_stb, input [7:0] set_addr, input [31:0] set_data,
@@ -31,23 +31,20 @@ module time_64bit
output [31:0] debug
);
- localparam NEXT_SECS = 0;
- localparam NEXT_TICKS = 1;
+ localparam NEXT_TICKS_HI = 0;
+ localparam NEXT_TICKS_LO = 1;
localparam PPS_POLSRC = 2;
localparam PPS_IMM = 3;
- localparam TPS = 4;
localparam MIMO_SYNC = 5;
- reg [31:0] seconds, ticks;
- wire end_of_second;
+ reg [63:0] ticks;
always @(posedge clk)
- vita_time <= {seconds,ticks};
+ vita_time <= ticks;
wire [63:0] vita_time_rcvd;
- wire [31:0] next_ticks_preset, next_seconds_preset;
- wire [31:0] ticks_per_sec_reg;
+ wire [63:0] next_ticks_preset;
wire set_on_pps_trig;
reg set_on_next_pps;
wire pps_polarity, pps_source, set_imm;
@@ -57,18 +54,18 @@ module time_64bit
reg [15:0] sync_counter;
wire sync_rcvd;
- wire [31:0] mimo_secs, mimo_ticks;
+ wire [63:0] mimo_ticks;
wire mimo_sync_now;
wire mimo_sync;
wire [7:0] sync_delay;
- setting_reg #(.my_addr(BASE+NEXT_TICKS)) sr_next_ticks
+ setting_reg #(.my_addr(BASE+NEXT_TICKS_LO)) sr_next_ticks_lo
(.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr),
- .in(set_data),.out(next_ticks_preset),.changed());
+ .in(set_data),.out(next_ticks_preset[31:0]),.changed());
- setting_reg #(.my_addr(BASE+NEXT_SECS)) sr_next_secs
+ setting_reg #(.my_addr(BASE+NEXT_TICKS_HI)) sr_next_ticks_hi
(.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr),
- .in(set_data),.out(next_seconds_preset),.changed(set_on_pps_trig));
+ .in(set_data),.out(next_ticks_preset[63:32]),.changed(set_on_pps_trig));
setting_reg #(.my_addr(BASE+PPS_POLSRC), .width(2)) sr_pps_polsrc
(.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr),
@@ -78,10 +75,6 @@ module time_64bit
(.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr),
.in(set_data),.out(set_imm),.changed());
- setting_reg #(.my_addr(BASE+TPS), .at_reset(TICKS_PER_SEC)) sr_tps
- (.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr),
- .in(set_data),.out(ticks_per_sec_reg),.changed());
-
setting_reg #(.my_addr(BASE+MIMO_SYNC), .at_reset(0), .width(9)) sr_mimosync
(.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr),
.in(set_data),.out({mimo_sync,sync_delay}),.changed());
@@ -110,29 +103,21 @@ module time_64bit
else if(set_imm | pps_edge)
set_on_next_pps <= 0;
- wire [31:0] ticks_plus_one = ticks + 1;
+ wire [63:0] ticks_plus_one = ticks + 1;
always @(posedge clk)
if(rst)
begin
- seconds <= 32'd0;
- ticks <= 32'd0;
+ ticks <= 64'd0;
end
else if((set_imm | pps_edge) & set_on_next_pps)
begin
- seconds <= next_seconds_preset;
ticks <= next_ticks_preset;
end
else if(mimo_sync_now)
begin
- seconds <= mimo_secs;
ticks <= mimo_ticks;
end
- else if(ticks_plus_one == ticks_per_sec_reg)
- begin
- seconds <= seconds + 1;
- ticks <= 0;
- end
else
ticks <= ticks_plus_one;
@@ -162,9 +147,8 @@ module time_64bit
.sync_rcvd(sync_rcvd),
.exp_time_in(exp_time_in) );
- assign mimo_secs = vita_time_rcvd[63:32];
- assign mimo_ticks = vita_time_rcvd[31:0] + {16'd0,sync_delay};
- assign mimo_sync_now = mimo_sync & sync_rcvd & (mimo_ticks <= TICKS_PER_SEC);
+ assign mimo_ticks = vita_time_rcvd[63:0] + {48'd0,sync_delay};
+ assign mimo_sync_now = mimo_sync & sync_rcvd;
assign debug = { { 24'b0} ,
{ 2'b0, exp_time_in, exp_time_out, mimo_sync, mimo_sync_now, sync_rcvd, send_sync} };
diff --git a/fpga/usrp2/timing/time_compare.v b/fpga/usrp2/timing/time_compare.v
index 54ea000d6..21607f51c 100644
--- a/fpga/usrp2/timing/time_compare.v
+++ b/fpga/usrp2/timing/time_compare.v
@@ -1,5 +1,5 @@
//
-// Copyright 2011 Ettus Research LLC
+// Copyright 2011-2012 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
@@ -16,49 +16,19 @@
//
-// Top 32 bits are integer seconds, bottom 32 are clock ticks within a second
+// 64 bits worth of ticks
module time_compare
(input [63:0] time_now,
input [63:0] trigger_time,
output now,
output early,
- output late,
+ output late,
output too_early);
-
- wire sec_match = (time_now[63:32] == trigger_time[63:32]);
- wire sec_late = (time_now[63:32] > trigger_time[63:32]);
- wire tick_match = (time_now[31:0] == trigger_time[31:0]);
- wire tick_late = (time_now[31:0] > trigger_time[31:0]);
-/*
- assign now = sec_match & tick_match;
- assign late = sec_late | (sec_match & tick_late);
- assign early = ~now & ~late;
-*/
+ assign now = time_now == trigger_time;
+ assign late = time_now > trigger_time;
+ assign early = ~now & ~late;
+ assign too_early = 0; //not implemented
- /*
- assign now = (time_now == trigger_time);
- assign late = (time_now > trigger_time);
- assign early = (time_now < trigger_time);
- */
-
- // Compare fewer bits instead of 64 to speed up logic
- // Unused bits are not significant
- // Top bit of seconds would put us in year 2038, long after
- // the warranty has run out :)
- // Top 5 bits of ticks are always zero for clocks less than 134MHz
- // "late" can drop bottom few bits of ticks, and just delay signaling
- // of late.
- // "now" cannot drop those bits, it needs to be exact.
-
- wire [57:0] short_now = {time_now[62:32],time_now[26:0]};
- wire [57:0] short_trig = {trigger_time[62:32],trigger_time[26:0]};
-
- assign now = (short_now == short_trig);
- assign late = (short_now[57:5] > short_trig[57:5]);
- assign early = (short_now < short_trig);
-
- assign too_early = (trigger_time[63:32] > (time_now[63:32] + 4)); // Don't wait too long
-
endmodule // time_compare
diff --git a/fpga/usrp2/top/B100/B100.ucf b/fpga/usrp2/top/B100/B100.ucf
index 69fd49971..1c04c5d8d 100644
--- a/fpga/usrp2/top/B100/B100.ucf
+++ b/fpga/usrp2/top/B100/B100.ucf
@@ -25,6 +25,9 @@ NET "reset_n" LOC = "D5" ;
NET "PPS_IN" LOC = "M14" ;
NET "reset_codec" LOC = "B14" ;
+## recycles fpga_cfg_cclk for reset from fw
+NET "ext_reset" LOC = "R14" ;
+
## GPIF
NET "GPIF_D<15>" LOC = "P7" ;
NET "GPIF_D<14>" LOC = "N8" ;
@@ -43,17 +46,18 @@ NET "GPIF_D<2>" LOC = "N9" ;
NET "GPIF_D<1>" LOC = "P9" ;
NET "GPIF_D<0>" LOC = "P8" ;
-NET "GPIF_CTL<3>" LOC = "N5" ;
+##NET "GPIF_CTL<3>" LOC = "N5" ;
+NET "GPIF_CTL<3>" LOC = "P12" ;
NET "GPIF_CTL<2>" LOC = "M11" ;
NET "GPIF_CTL<1>" LOC = "M9" ;
NET "GPIF_CTL<0>" LOC = "M7" ;
-NET "GPIF_RDY<3>" LOC = "N11" ;
-NET "GPIF_RDY<2>" LOC = "T10" ;
-NET "GPIF_RDY<1>" LOC = "T4" ;
-NET "GPIF_RDY<0>" LOC = "R5" ;
+##NET "GPIF_RDY<3>" LOC = "N11" ;
+##NET "GPIF_RDY<2>" LOC = "T10" ;
+NET "GPIF_SLWR" LOC = "T4" ;
+NET "GPIF_SLRD" LOC = "R5" ;
-NET "GPIF_CS" LOC = "P12" ;
+##NET "GPIF_CS" LOC = "P12" ;
NET "GPIF_SLOE" LOC = "R11" ;
NET "GPIF_PKTEND" LOC = "P10" ;
NET "GPIF_ADR<0>" LOC = "T11" ;
diff --git a/fpga/usrp2/top/B100/B100.v b/fpga/usrp2/top/B100/B100.v
index f2d75c54e..dcda974b4 100644
--- a/fpga/usrp2/top/B100/B100.v
+++ b/fpga/usrp2/top/B100/B100.v
@@ -23,8 +23,8 @@ module B100
output [2:0] debug_led, output [31:0] debug, output [1:0] debug_clk,
// GPIF
- inout [15:0] GPIF_D, input [3:0] GPIF_CTL, output [3:0] GPIF_RDY,
- input [1:0] GPIF_ADR, output GPIF_CS, output GPIF_SLOE, output GPIF_PKTEND,
+ inout [15:0] GPIF_D, input [3:0] GPIF_CTL, output GPIF_SLOE,
+ output [1:0] GPIF_ADR, output GPIF_SLWR, output GPIF_SLRD, output GPIF_PKTEND,
input IFCLK,
inout SDA_FPGA, inout SCL_FPGA, // I2C
@@ -41,7 +41,8 @@ module B100
input [11:0] adc, input RXSYNC,
input PPS_IN,
- input reset_n, output reset_codec
+ input reset_n, output reset_codec,
+ input ext_reset
);
assign reset_codec = 1; // Believed to be active low
@@ -55,7 +56,7 @@ module B100
BUFG clk_fpga_BUFG (.I(clk_fpga_in), .O(clk_fpga));
- reset_sync reset_sync(.clk(clk_fpga), .reset_in(~reset_n), .reset_out(reset));
+ reset_sync reset_sync(.clk(clk_fpga), .reset_in((~reset_n) | (~ext_reset)), .reset_out(reset));
// /////////////////////////////////////////////////////////////////////////
// SPI
@@ -156,9 +157,10 @@ module B100
u1plus_core u1p_c(.clk_fpga(clk_fpga), .rst_fpga(reset),
.debug_led(debug_led), .debug(debug), .debug_clk(debug_clk),
.debug_txd(), .debug_rxd(1'b1),
- .gpif_d(GPIF_D), .gpif_ctl(GPIF_CTL), .gpif_rdy(GPIF_RDY),
- .gpif_misc({GPIF_CS,GPIF_SLOE,GPIF_PKTEND}),
- .gpif_clk(IFCLK),
+
+ .gpif_d(GPIF_D), .gpif_ctl(GPIF_CTL), .gpif_pktend(GPIF_PKTEND),
+ .gpif_sloe(GPIF_SLOE), .gpif_slwr(GPIF_SLWR), .gpif_slrd(GPIF_SLRD),
+ .gpif_fifoadr(GPIF_ADR), .gpif_clk(IFCLK),
.db_sda(SDA_FPGA), .db_scl(SCL_FPGA),
.sclk(sclk), .sen({SEN_CODEC,SEN_TX_DB,SEN_RX_DB}), .mosi(mosi), .miso(miso),
diff --git a/fpga/usrp2/top/B100/Makefile.B100 b/fpga/usrp2/top/B100/Makefile.B100
index 90dd25942..3cdbb62c0 100644
--- a/fpga/usrp2/top/B100/Makefile.B100
+++ b/fpga/usrp2/top/B100/Makefile.B100
@@ -1,5 +1,5 @@
#
-# Copyright 2008 Ettus Research LLC
+# Copyright 2008-2012 Ettus Research LLC
#
##################################################
@@ -7,7 +7,14 @@
##################################################
TOP_MODULE := B100
BUILD_DIR := build-B100/
-export PROJ_FILE := $(BUILD_DIR)$(TOP_MODULE).ise
+
+# set me in a custom makefile
+CUSTOM_SRCS =
+CUSTOM_DEFS =
+
+##################################################
+# Include other makefiles
+##################################################
include ../Makefile.common
include ../../fifo/Makefile.srcs
@@ -50,7 +57,7 @@ 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) $(EXTRAM_SRCS) \
-$(GPIF_SRCS)
+$(GPIF_SRCS) $(CUSTOM_SRCS)
##################################################
# Process Properties
@@ -63,7 +70,8 @@ SYNTHESIZE_PROPERTIES = \
"Register Balancing" Yes \
"Use Clock Enable" Auto \
"Use Synchronous Reset" Auto \
-"Use Synchronous Set" Auto
+"Use Synchronous Set" Auto \
+"Verilog Macros" "$(CUSTOM_MOD_DEFS)"
TRANSLATE_PROPERTIES = \
"Macro Search Path" "$(shell pwd)/../../coregen/"
diff --git a/fpga/usrp2/top/B100/core_compile b/fpga/usrp2/top/B100/core_compile
index b2ccc8b49..b62cbaee0 100755
--- a/fpga/usrp2/top/B100/core_compile
+++ b/fpga/usrp2/top/B100/core_compile
@@ -1 +1 @@
-iverilog -Wall -y. -y ../../control_lib/ -y ../../fifo/ -y ../../gpif/ -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 u1plus_core.v 2>&1 | grep -v timescale | grep -v coregen | grep -v models
+iverilog -Wall -y. -y ../../control_lib/ -y ../../custom/ -y ../../fifo/ -y ../../gpif/ -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 u1plus_core.v 2>&1 | grep -v timescale | grep -v coregen | grep -v models
diff --git a/fpga/usrp2/top/B100/timing.ucf b/fpga/usrp2/top/B100/timing.ucf
index b2a455f6d..96c47cf2c 100644
--- a/fpga/usrp2/top/B100/timing.ucf
+++ b/fpga/usrp2/top/B100/timing.ucf
@@ -3,3 +3,12 @@ TIMESPEC "TS_CLK_FPGA_P" = PERIOD "CLK_FPGA_P" 15625 ps HIGH 50 %;
NET "IFCLK" TNM_NET = "IFCLK";
TIMESPEC "TS_IFCLK" = PERIOD "IFCLK" 20833 ps HIGH 50 %;
+
+#constrain FX2 IO
+NET "GPIF_D<*>" MAXDELAY = 5.5 ns;
+NET "GPIF_CTL<*>" MAXDELAY = 5.5 ns;
+NET "GPIF_ADR<*>" MAXDELAY = 5.5ns;
+NET "GPIF_SLWR" MAXDELAY = 5.5 ns;
+NET "GPIF_SLRD" MAXDELAY = 5.5 ns;
+NET "GPIF_SLOE" MAXDELAY = 5.5 ns;
+NET "GPIF_PKTEND" MAXDELAY = 5.5 ns;
diff --git a/fpga/usrp2/top/B100/u1plus_core.v b/fpga/usrp2/top/B100/u1plus_core.v
index c883c5ca8..e335fb8bb 100644
--- a/fpga/usrp2/top/B100/u1plus_core.v
+++ b/fpga/usrp2/top/B100/u1plus_core.v
@@ -1,5 +1,5 @@
//
-// Copyright 2011 Ettus Research LLC
+// Copyright 2011-2012 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
@@ -23,8 +23,9 @@ module u1plus_core
output debug_txd, input debug_rxd,
// GPIF
- inout [15:0] gpif_d, input [3:0] gpif_ctl, output [3:0] gpif_rdy,
- output [2:0] gpif_misc, input gpif_clk,
+ inout [15:0] gpif_d, input [3:0] gpif_ctl, output gpif_sloe,
+ output gpif_slwr, output gpif_slrd, output gpif_pktend, output [1:0] gpif_fifoadr,
+ input gpif_clk,
inout db_sda, inout db_scl,
output sclk, output [15:0] sen, output mosi, input miso,
@@ -37,7 +38,7 @@ module u1plus_core
);
localparam TXFIFOSIZE = 11;
- localparam RXFIFOSIZE = 11;
+ localparam RXFIFOSIZE = 12;
// 64 total regs in address space
localparam SR_RX_CTRL0 = 0; // 9 regs (+0 to +8)
@@ -52,9 +53,9 @@ module u1plus_core
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_CLEAR_FIFO = 61; // 1 reg
localparam SR_GLOBAL_RESET = 63; // 1 reg
+ localparam SR_USER_REGS = 64; // 2 regs
localparam SR_GPIO = 128; // 5 regs
@@ -64,11 +65,11 @@ module u1plus_core
wire pps_int;
wire [63:0] vita_time, vita_time_pps;
reg [15:0] reg_cgen_ctrl, reg_test;
-
- wire [7:0] set_addr;
- wire [31:0] set_data;
- wire set_stb;
-
+
+ wire [7:0] set_addr, set_addr_user;
+ wire [31:0] set_data, set_data_user;
+ wire set_stb, set_stb_user;
+
wire [31:0] debug0;
wire [31:0] debug1;
@@ -105,68 +106,70 @@ module u1plus_core
wire tx_src_rdy, tx_dst_rdy, rx_src_rdy, rx_dst_rdy,
tx_err_src_rdy, tx_err_dst_rdy;
- wire clear_tx, clear_rx;
-
- setting_reg #(.my_addr(SR_CLEAR_RX_FIFO), .width(1)) sr_clear_rx
- (.clk(wb_clk),.rst(wb_rst),.strobe(set_stb),.addr(set_addr),
- .in(set_data),.out(),.changed(clear_rx));
+ wire clear_fifo;
- setting_reg #(.my_addr(SR_CLEAR_TX_FIFO), .width(1)) sr_clear_tx
+ setting_reg #(.my_addr(SR_CLEAR_FIFO), .width(1)) sr_clear_fifo
(.clk(wb_clk),.rst(wb_rst),.strobe(set_stb),.addr(set_addr),
- .in(set_data),.out(),.changed(clear_tx));
+ .in(set_data),.out(),.changed(clear_fifo));
- gpif #(.TXFIFOSIZE(TXFIFOSIZE), .RXFIFOSIZE(RXFIFOSIZE))
- gpif (.gpif_clk(gpif_clk), .gpif_rst(gpif_rst), .gpif_d(gpif_d),
- .gpif_ctl(gpif_ctl), .gpif_rdy(gpif_rdy), .gpif_misc(gpif_misc),
+ wire run_rx0, run_rx1;
+
+ slave_fifo #(.TXFIFOSIZE(TXFIFOSIZE), .RXFIFOSIZE(RXFIFOSIZE))
+ slave_fifo (.gpif_clk(gpif_clk), .gpif_rst(gpif_rst), .gpif_d(gpif_d),
+ .gpif_ctl(gpif_ctl), .sloe(gpif_sloe), .slwr(gpif_slwr), .slrd(gpif_slrd),
+ .pktend(gpif_pktend), .fifoadr(gpif_fifoadr),
.wb_clk(wb_clk), .wb_rst(wb_rst),
.wb_adr_o(m0_adr), .wb_dat_mosi(m0_dat_mosi), .wb_dat_miso(m0_dat_miso),
.wb_sel_o(m0_sel), .wb_cyc_o(m0_cyc), .wb_stb_o(m0_stb), .wb_we_o(m0_we),
.wb_ack_i(m0_ack), .triggers(8'd0),
- .fifo_clk(wb_clk), .fifo_rst(wb_rst), .clear_tx(clear_tx), .clear_rx(clear_rx),
+ .dsp_rx_run(run_rx0 | run_rx1),
+
+ .fifo_clk(wb_clk), .fifo_rst(wb_rst), .clear_tx(clear_fifo), .clear_rx(clear_fifo),
.tx_data_o(tx_data), .tx_src_rdy_o(tx_src_rdy), .tx_dst_rdy_i(tx_dst_rdy),
.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_gpif), .rx_overrun(rx_overrun_gpif),
- .frames_per_packet(frames_per_packet),
+ .test_len(0), .test_rate(0), .test_ctrl(0),
.debug0(debug0), .debug1(debug1));
// /////////////////////////////////////////////////////////////////////////
// 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_rx0, run_rx1;
-
+ wire [23:0] rx_fe_i, rx_fe_q; // 24 bits is total overkill here, but it matches u2/u2p
+
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());
+ .i_out(rx_fe_i), .q_out(rx_fe_q), .run(run_rx0 | run_rx1), .debug());
// /////////////////////////////////////////////////////////////////////////
// DSP RX 0
wire [31:0] sample_rx0;
- wire strobe_rx0;
+ wire strobe_rx0, clear_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),
+ ddc_chain #(.BASE(SR_RX_DSP0), .DSPNO(0)) ddc_chain0
+ (.clk(wb_clk), .rst(wb_rst), .clr(clear_rx0),
.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),
+ .set_stb_user(set_stb_user), .set_addr_user(set_addr_user), .set_data_user(set_data_user),
+ .rx_fe_i(rx_fe_i),.rx_fe_q(rx_fe_q),
.sample(sample_rx0), .run(run_rx0), .strobe(strobe_rx0),
.debug() );
- vita_rx_chain #(.BASE(SR_RX_CTRL0), .UNIT(0), .FIFOSIZE(10), .PROT_ENG_FLAGS(0)) vita_rx_chain0
- (.clk(wb_clk),.reset(wb_rst),.clear(clear_rx),
+ vita_rx_chain #(.BASE(SR_RX_CTRL0), .UNIT(0), .FIFOSIZE(10), .PROT_ENG_FLAGS(0), .DSP_NUMBER(0)) vita_rx_chain0
+ (.clk(wb_clk),.reset(wb_rst),
.set_stb(set_stb),.set_addr(set_addr),.set_data(set_data),
+ .set_stb_user(set_stb_user), .set_addr_user(set_addr_user), .set_data_user(set_data_user),
.vita_time(vita_time), .overrun(rx_overrun_dsp0),
- .sample(sample_rx0), .run(run_rx0), .strobe(strobe_rx0),
+ .sample(sample_rx0), .run(run_rx0), .strobe(strobe_rx0), .clear_o(clear_rx0),
.rx_data_o(vita_rx_data0), .rx_dst_rdy_i(vita_rx_dst_rdy0), .rx_src_rdy_o(vita_rx_src_rdy0),
.debug() );
@@ -174,22 +177,24 @@ module u1plus_core
// DSP RX 1
wire [31:0] sample_rx1;
- wire strobe_rx1;
+ wire strobe_rx1, clear_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),
+ ddc_chain #(.BASE(SR_RX_DSP1), .DSPNO(1)) ddc_chain1
+ (.clk(wb_clk),.rst(wb_rst), .clr(clear_rx1),
.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),
+ .set_stb_user(set_stb_user), .set_addr_user(set_addr_user), .set_data_user(set_data_user),
+ .rx_fe_i(rx_fe_i),.rx_fe_q(rx_fe_q),
.sample(sample_rx1), .run(run_rx1), .strobe(strobe_rx1),
.debug() );
- vita_rx_chain #(.BASE(SR_RX_CTRL1), .UNIT(1), .FIFOSIZE(10), .PROT_ENG_FLAGS(0)) vita_rx_chain1
- (.clk(wb_clk),.reset(wb_rst),.clear(clear_rx),
+ vita_rx_chain #(.BASE(SR_RX_CTRL1), .UNIT(1), .FIFOSIZE(10), .PROT_ENG_FLAGS(0), .DSP_NUMBER(1)) vita_rx_chain1
+ (.clk(wb_clk),.reset(wb_rst),
.set_stb(set_stb),.set_addr(set_addr),.set_data(set_data),
+ .set_stb_user(set_stb_user), .set_addr_user(set_addr_user), .set_data_user(set_data_user),
.vita_time(vita_time), .overrun(rx_overrun_dsp1),
- .sample(sample_rx1), .run(run_rx1), .strobe(strobe_rx1),
+ .sample(sample_rx1), .run(run_rx1), .strobe(strobe_rx1), .clear_o(clear_rx1),
.rx_data_o(vita_rx_data1), .rx_dst_rdy_i(vita_rx_dst_rdy1), .rx_src_rdy_o(vita_rx_src_rdy1),
.debug() );
@@ -197,7 +202,7 @@ module u1plus_core
// RX Stream muxing
fifo36_mux #(.prio(0)) mux_data_streams
- (.clk(wb_clk), .reset(wb_rst), .clear(0),
+ (.clk(wb_clk), .reset(wb_rst), .clear(clear_fifo),
.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));
@@ -205,27 +210,38 @@ module u1plus_core
// ///////////////////////////////////////////////////////////////////////////////////
// DSP TX
- 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),
+ wire [23:0] tx_fe_i, tx_fe_q;
+ wire [31:0] sample_tx;
+ wire strobe_tx, clear_tx;
+
+ vita_tx_chain #(.BASE(SR_TX_CTRL), .FIFOSIZE(10), .POST_ENGINE_FIFOSIZE(11),
.REPORT_ERROR(1), .DO_FLOW_CONTROL(0),
.PROT_ENG_FLAGS(0), .USE_TRANS_HEADER(0),
.DSP_NUMBER(0))
vita_tx_chain
(.clk(wb_clk), .reset(wb_rst),
.set_stb(set_stb),.set_addr(set_addr),.set_data(set_data),
+ .set_stb_user(set_stb_user), .set_addr_user(set_addr_user), .set_data_user(set_data_user),
.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),
- .tx_i(tx_i_int),.tx_q(tx_q_int),
- .underrun(tx_underrun_dsp), .run(run_tx),
+ .sample(sample_tx), .strobe(strobe_tx),
+ .underrun(tx_underrun_dsp), .run(run_tx), .clear_o(clear_tx),
.debug(debug_vt));
+ duc_chain #(.BASE(SR_TX_DSP), .DSPNO(0)) duc_chain
+ (.clk(wb_clk), .rst(wb_rst), .clr(clear_tx),
+ .set_stb(set_stb),.set_addr(set_addr),.set_data(set_data),
+ .set_stb_user(set_stb_user), .set_addr_user(set_addr_user), .set_data_user(set_data_user),
+ .tx_fe_i(tx_fe_i),.tx_fe_q(tx_fe_q),
+ .sample(sample_tx), .run(run_tx), .strobe(strobe_tx),
+ .debug() );
+
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),
+ .tx_i(tx_fe_i), .tx_q(tx_fe_q), .run(1'b1),
.dac_a(tx_i), .dac_b(tx_q));
// /////////////////////////////////////////////////////////////////////////////////////
@@ -387,11 +403,17 @@ module u1plus_core
.wb_stb_i(s8_stb),.wb_we_i(s8_we),.wb_ack_o(s8_ack),
.strobe(set_stb),.addr(set_addr),.data(set_data) );
+ user_settings #(.BASE(SR_USER_REGS)) user_settings
+ (.clk(wb_clk),.rst(wb_rst),.set_stb(set_stb),
+ .set_addr(set_addr),.set_data(set_data),
+ .set_addr_user(set_addr_user),.set_data_user(set_data_user),
+ .set_stb_user(set_stb_user) );
+
// /////////////////////////////////////////////////////////////////////////
// Readback mux 32 -- Slave #7
//compatibility number -> increment when the fpga has been sufficiently altered
- localparam compat_num = {16'd8, 16'd1}; //major, minor
+ localparam compat_num = {16'd9, 16'd0}; //major, minor
wire [31:0] reg_test32;
@@ -416,7 +438,7 @@ module u1plus_core
// /////////////////////////////////////////////////////////////////////////
// VITA Timing
- time_64bit #(.TICKS_PER_SEC(32'd64000000),.BASE(SR_TIME64)) time_64bit
+ time_64bit #(.BASE(SR_TIME64)) time_64bit
(.clk(wb_clk), .rst(wb_rst), .set_stb(set_stb), .set_addr(set_addr), .set_data(set_data),
.pps(pps_in), .vita_time(vita_time), .vita_time_pps(vita_time_pps), .pps_int(pps_int),
.exp_time_in(0));
diff --git a/fpga/usrp2/top/E1x0/Makefile.E100 b/fpga/usrp2/top/E1x0/Makefile.E100
index 9b9a48911..ad5a0c1bd 100644
--- a/fpga/usrp2/top/E1x0/Makefile.E100
+++ b/fpga/usrp2/top/E1x0/Makefile.E100
@@ -1,5 +1,5 @@
#
-# Copyright 2008 Ettus Research LLC
+# Copyright 2008-2012 Ettus Research LLC
#
##################################################
@@ -8,6 +8,10 @@
TOP_MODULE = u1e
BUILD_DIR = $(abspath build$(ISE)-E100)
+# set me in a custom makefile
+CUSTOM_SRCS =
+CUSTOM_DEFS =
+
##################################################
# Include other makefiles
##################################################
@@ -53,7 +57,7 @@ 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) $(EXTRAM_SRCS) \
-$(GPMC_SRCS)
+$(GPMC_SRCS) $(CUSTOM_SRCS)
##################################################
# Process Properties
@@ -66,7 +70,8 @@ SYNTHESIZE_PROPERTIES = \
"Register Balancing" Yes \
"Use Clock Enable" Auto \
"Use Synchronous Reset" Auto \
-"Use Synchronous Set" Auto
+"Use Synchronous Set" Auto \
+"Verilog Macros" "$(CUSTOM_MOD_DEFS)"
TRANSLATE_PROPERTIES = \
"Macro Search Path" "$(shell pwd)/../../coregen/"
diff --git a/fpga/usrp2/top/E1x0/Makefile.E110 b/fpga/usrp2/top/E1x0/Makefile.E110
index be2761baf..291ac0a44 100644
--- a/fpga/usrp2/top/E1x0/Makefile.E110
+++ b/fpga/usrp2/top/E1x0/Makefile.E110
@@ -1,5 +1,5 @@
#
-# Copyright 2008 Ettus Research LLC
+# Copyright 2008-2012 Ettus Research LLC
#
##################################################
@@ -8,6 +8,10 @@
TOP_MODULE = u1e
BUILD_DIR = $(abspath build$(ISE)-E110)
+# set me in a custom makefile
+CUSTOM_SRCS =
+CUSTOM_DEFS =
+
##################################################
# Include other makefiles
##################################################
@@ -53,7 +57,7 @@ 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) $(EXTRAM_SRCS) \
-$(GPMC_SRCS)
+$(GPMC_SRCS) $(CUSTOM_SRCS)
##################################################
# Process Properties
@@ -66,7 +70,8 @@ SYNTHESIZE_PROPERTIES = \
"Register Balancing" Yes \
"Use Clock Enable" Auto \
"Use Synchronous Reset" Auto \
-"Use Synchronous Set" Auto
+"Use Synchronous Set" Auto \
+"Verilog Macros" "$(CUSTOM_MOD_DEFS)"
TRANSLATE_PROPERTIES = \
"Macro Search Path" "$(shell pwd)/../../coregen/"
diff --git a/fpga/usrp2/top/E1x0/core_compile b/fpga/usrp2/top/E1x0/core_compile
index 02d7f006e..14e138fa3 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 -y $XILINX/verilog/src/unisims u1e_core.v 2>&1 | grep -v timescale | grep -v coregen | grep -v models
+iverilog -Wall -y. -y ../../control_lib/ -y ../../custom/ -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/u1e_core.v b/fpga/usrp2/top/E1x0/u1e_core.v
index aede63bac..ee27af939 100644
--- a/fpga/usrp2/top/E1x0/u1e_core.v
+++ b/fpga/usrp2/top/E1x0/u1e_core.v
@@ -1,5 +1,5 @@
//
-// Copyright 2011 Ettus Research LLC
+// Copyright 2011-2012 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
@@ -56,9 +56,9 @@ module u1e_core
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_CLEAR_FIFO = 61; // 1 reg
localparam SR_GLOBAL_RESET = 63; // 1 reg
+ localparam SR_USER_REGS = 64; // 2 regs
localparam SR_GPIO = 128; // 5 regs
@@ -70,10 +70,10 @@ module u1e_core
reg [15:0] reg_cgen_ctrl, reg_test, xfer_rate;
wire [7:0] test_rate;
wire [3:0] test_ctrl;
-
- wire [7:0] set_addr;
- wire [31:0] set_data;
- wire set_stb;
+
+ wire [7:0] set_addr, set_addr_user;
+ wire [31:0] set_data, set_data_user;
+ wire set_stb, set_stb_user;
wire [31:0] debug_vt;
wire rx_overrun_dsp0, rx_overrun_dsp1, rx_overrun_gpmc, tx_underrun_dsp, tx_underrun_gpmc;
@@ -103,15 +103,13 @@ module u1e_core
wire tx_src_rdy, tx_dst_rdy, rx_src_rdy, rx_dst_rdy,
tx_err_src_rdy, tx_err_dst_rdy;
- wire clear_tx, clear_rx;
-
- setting_reg #(.my_addr(SR_CLEAR_RX_FIFO), .width(1)) sr_clear_rx
- (.clk(wb_clk),.rst(wb_rst),.strobe(set_stb),.addr(set_addr),
- .in(set_data),.out(),.changed(clear_rx));
+ wire clear_fifo;
- setting_reg #(.my_addr(SR_CLEAR_TX_FIFO), .width(1)) sr_clear_tx
+ setting_reg #(.my_addr(SR_CLEAR_FIFO), .width(1)) sr_clear_fifo
(.clk(wb_clk),.rst(wb_rst),.strobe(set_stb),.addr(set_addr),
- .in(set_data),.out(),.changed(clear_tx));
+ .in(set_data),.out(),.changed(clear_fifo));
+
+ wire run_rx0, run_rx1;
gpmc #(.TXFIFOSIZE(TXFIFOSIZE), .RXFIFOSIZE(RXFIFOSIZE))
gpmc (.arst(wb_rst),
@@ -126,7 +124,7 @@ module u1e_core
.wb_sel_o(m0_sel), .wb_cyc_o(m0_cyc), .wb_stb_o(m0_stb), .wb_we_o(m0_we),
.wb_ack_i(m0_ack),
- .fifo_clk(wb_clk), .fifo_rst(wb_rst), .clear_tx(clear_tx), .clear_rx(clear_rx),
+ .fifo_clk(wb_clk), .fifo_rst(wb_rst), .clear_tx(clear_fifo), .clear_rx(clear_fifo),
.tx_data_o(tx_data), .tx_src_rdy_o(tx_src_rdy), .tx_dst_rdy_i(tx_dst_rdy),
.rx_data_i(rx_data), .rx_src_rdy_i(rx_src_rdy), .rx_dst_rdy_o(rx_dst_rdy),
@@ -142,36 +140,37 @@ module u1e_core
// /////////////////////////////////////////////////////////////////////////
// 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_rx0, run_rx1;
-
+ wire [23:0] rx_fe_i, rx_fe_q; // 24 bits is total overkill here, but it matches u2/u2p
+
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());
+ .i_out(rx_fe_i), .q_out(rx_fe_q), .run(run_rx0 | run_rx1), .debug());
// /////////////////////////////////////////////////////////////////////////
// DSP RX 0
wire [31:0] sample_rx0;
- wire strobe_rx0;
+ wire strobe_rx0, clear_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),
+ ddc_chain #(.BASE(SR_RX_DSP0), .DSPNO(0)) ddc_chain0
+ (.clk(wb_clk), .rst(wb_rst), .clr(clear_rx0),
.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),
+ .set_stb_user(set_stb_user), .set_addr_user(set_addr_user), .set_data_user(set_data_user),
+ .rx_fe_i(rx_fe_i),.rx_fe_q(rx_fe_q),
.sample(sample_rx0), .run(run_rx0), .strobe(strobe_rx0),
.debug() );
- vita_rx_chain #(.BASE(SR_RX_CTRL0), .UNIT(0), .FIFOSIZE(10), .PROT_ENG_FLAGS(0)) vita_rx_chain0
- (.clk(wb_clk),.reset(wb_rst),.clear(clear_rx),
+ vita_rx_chain #(.BASE(SR_RX_CTRL0), .UNIT(0), .FIFOSIZE(10), .PROT_ENG_FLAGS(0), .DSP_NUMBER(0)) vita_rx_chain0
+ (.clk(wb_clk),.reset(wb_rst),
.set_stb(set_stb),.set_addr(set_addr),.set_data(set_data),
+ .set_stb_user(set_stb_user), .set_addr_user(set_addr_user), .set_data_user(set_data_user),
.vita_time(vita_time), .overrun(rx_overrun_dsp0),
- .sample(sample_rx0), .run(run_rx0), .strobe(strobe_rx0),
+ .sample(sample_rx0), .run(run_rx0), .strobe(strobe_rx0), .clear_o(clear_rx0),
.rx_data_o(vita_rx_data0), .rx_dst_rdy_i(vita_rx_dst_rdy0), .rx_src_rdy_o(vita_rx_src_rdy0),
.debug() );
@@ -179,22 +178,24 @@ module u1e_core
// DSP RX 1
wire [31:0] sample_rx1;
- wire strobe_rx1;
+ wire strobe_rx1, clear_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),
+ ddc_chain #(.BASE(SR_RX_DSP1), .DSPNO(1)) ddc_chain1
+ (.clk(wb_clk),.rst(wb_rst), .clr(clear_rx1),
.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),
+ .set_stb_user(set_stb_user), .set_addr_user(set_addr_user), .set_data_user(set_data_user),
+ .rx_fe_i(rx_fe_i),.rx_fe_q(rx_fe_q),
.sample(sample_rx1), .run(run_rx1), .strobe(strobe_rx1),
.debug() );
- vita_rx_chain #(.BASE(SR_RX_CTRL1), .UNIT(1), .FIFOSIZE(10), .PROT_ENG_FLAGS(0)) vita_rx_chain1
- (.clk(wb_clk),.reset(wb_rst),.clear(clear_rx),
+ vita_rx_chain #(.BASE(SR_RX_CTRL1), .UNIT(1), .FIFOSIZE(10), .PROT_ENG_FLAGS(0), .DSP_NUMBER(1)) vita_rx_chain1
+ (.clk(wb_clk),.reset(wb_rst),
.set_stb(set_stb),.set_addr(set_addr),.set_data(set_data),
+ .set_stb_user(set_stb_user), .set_addr_user(set_addr_user), .set_data_user(set_data_user),
.vita_time(vita_time), .overrun(rx_overrun_dsp1),
- .sample(sample_rx1), .run(run_rx1), .strobe(strobe_rx1),
+ .sample(sample_rx1), .run(run_rx1), .strobe(strobe_rx1), .clear_o(clear_rx1),
.rx_data_o(vita_rx_data1), .rx_dst_rdy_i(vita_rx_dst_rdy1), .rx_src_rdy_o(vita_rx_src_rdy1),
.debug() );
@@ -202,7 +203,7 @@ module u1e_core
// RX Stream muxing
fifo36_mux #(.prio(0)) mux_data_streams
- (.clk(wb_clk), .reset(wb_rst), .clear(0),
+ (.clk(wb_clk), .reset(wb_rst), .clear(clear_fifo),
.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));
@@ -210,27 +211,38 @@ module u1e_core
// ///////////////////////////////////////////////////////////////////////////////////
// DSP TX
- 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),
+ wire [23:0] tx_fe_i, tx_fe_q;
+ wire [31:0] sample_tx;
+ wire strobe_tx, clear_tx;
+
+ vita_tx_chain #(.BASE(SR_TX_CTRL), .FIFOSIZE(10), .POST_ENGINE_FIFOSIZE(11),
.REPORT_ERROR(1), .DO_FLOW_CONTROL(0),
.PROT_ENG_FLAGS(0), .USE_TRANS_HEADER(0),
.DSP_NUMBER(0))
vita_tx_chain
(.clk(wb_clk), .reset(wb_rst),
.set_stb(set_stb),.set_addr(set_addr),.set_data(set_data),
+ .set_stb_user(set_stb_user), .set_addr_user(set_addr_user), .set_data_user(set_data_user),
.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),
- .tx_i(tx_i_int),.tx_q(tx_q_int),
- .underrun(tx_underrun_dsp), .run(run_tx),
+ .sample(sample_tx), .strobe(strobe_tx),
+ .underrun(tx_underrun_dsp), .run(run_tx), .clear_o(clear_tx),
.debug(debug_vt));
+ duc_chain #(.BASE(SR_TX_DSP), .DSPNO(0)) duc_chain
+ (.clk(wb_clk), .rst(wb_rst), .clr(clear_tx),
+ .set_stb(set_stb),.set_addr(set_addr),.set_data(set_data),
+ .set_stb_user(set_stb_user), .set_addr_user(set_addr_user), .set_data_user(set_data_user),
+ .tx_fe_i(tx_fe_i),.tx_fe_q(tx_fe_q),
+ .sample(sample_tx), .run(run_tx), .strobe(strobe_tx),
+ .debug() );
+
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),
+ .tx_i(tx_fe_i), .tx_q(tx_fe_q), .run(1'b1),
.dac_a(tx_i), .dac_b(tx_q));
// /////////////////////////////////////////////////////////////////////////////////////
@@ -432,11 +444,17 @@ module u1e_core
.wb_stb_i(s8_stb),.wb_we_i(s8_we),.wb_ack_o(s8_ack),
.strobe(set_stb),.addr(set_addr),.data(set_data) );
+ user_settings #(.BASE(SR_USER_REGS)) user_settings
+ (.clk(wb_clk),.rst(wb_rst),.set_stb(set_stb),
+ .set_addr(set_addr),.set_data(set_data),
+ .set_addr_user(set_addr_user),.set_data_user(set_data_user),
+ .set_stb_user(set_stb_user) );
+
// /////////////////////////////////////////////////////////////////////////
// Readback mux 32 -- Slave #7
//compatibility number -> increment when the fpga has been sufficiently altered
- localparam compat_num = {16'd8, 16'd1}; //major, minor
+ localparam compat_num = {16'd9, 16'd0}; //major, minor
wire [31:0] reg_test32;
@@ -462,7 +480,7 @@ module u1e_core
// /////////////////////////////////////////////////////////////////////////
// VITA Timing
- time_64bit #(.TICKS_PER_SEC(32'd64000000),.BASE(SR_TIME64)) time_64bit
+ time_64bit #(.BASE(SR_TIME64)) time_64bit
(.clk(wb_clk), .rst(wb_rst), .set_stb(set_stb), .set_addr(set_addr), .set_data(set_data),
.pps(pps_in), .vita_time(vita_time), .vita_time_pps(vita_time_pps), .pps_int(pps_int),
.exp_time_in(0));
diff --git a/fpga/usrp2/top/N2x0/Makefile.N200R3 b/fpga/usrp2/top/N2x0/Makefile.N200R3
index 9ed5ece00..680cadf44 100644
--- a/fpga/usrp2/top/N2x0/Makefile.N200R3
+++ b/fpga/usrp2/top/N2x0/Makefile.N200R3
@@ -1,5 +1,5 @@
#
-# Copyright 2008 Ettus Research LLC
+# Copyright 2008-2012 Ettus Research LLC
#
##################################################
@@ -8,6 +8,10 @@
TOP_MODULE = u2plus
BUILD_DIR = $(abspath build$(ISE)-N200R3)
+# set me in a custom makefile
+CUSTOM_SRCS =
+CUSTOM_DEFS =
+
##################################################
# Include other makefiles
##################################################
@@ -52,7 +56,8 @@ u2plus.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) $(EXTRAM_SRCS)
+$(VRT_SRCS) $(UDP_SRCS) $(COREGEN_SRCS) $(EXTRAM_SRCS) \
+$(CUSTOM_SRCS)
##################################################
# Process Properties
@@ -65,7 +70,8 @@ SYNTHESIZE_PROPERTIES = \
"Register Balancing" Yes \
"Use Clock Enable" Auto \
"Use Synchronous Reset" Auto \
-"Use Synchronous Set" Auto
+"Use Synchronous Set" Auto \
+"Verilog Macros" "$(CUSTOM_DEFS)"
TRANSLATE_PROPERTIES = \
"Macro Search Path" "$(shell pwd)/../../coregen/"
diff --git a/fpga/usrp2/top/N2x0/Makefile.N200R4 b/fpga/usrp2/top/N2x0/Makefile.N200R4
index f8640224f..5c9ffd7a6 100644
--- a/fpga/usrp2/top/N2x0/Makefile.N200R4
+++ b/fpga/usrp2/top/N2x0/Makefile.N200R4
@@ -1,5 +1,5 @@
#
-# Copyright 2008 Ettus Research LLC
+# Copyright 2008-2012 Ettus Research LLC
#
##################################################
@@ -8,6 +8,10 @@
TOP_MODULE = u2plus
BUILD_DIR = $(abspath build$(ISE)-N200R4)
+# set me in a custom makefile
+CUSTOM_SRCS =
+CUSTOM_DEFS =
+
##################################################
# Include other makefiles
##################################################
@@ -53,7 +57,8 @@ u2plus.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) $(EXTRAM_SRCS)
+$(VRT_SRCS) $(UDP_SRCS) $(COREGEN_SRCS) $(EXTRAM_SRCS) \
+$(CUSTOM_SRCS)
##################################################
# Process Properties
@@ -67,7 +72,7 @@ SYNTHESIZE_PROPERTIES = \
"Use Clock Enable" Auto \
"Use Synchronous Reset" Auto \
"Use Synchronous Set" Auto \
-"Verilog Macros" "LVDS=1"
+"Verilog Macros" "LVDS=1 $(CUSTOM_DEFS)"
TRANSLATE_PROPERTIES = \
"Macro Search Path" "$(shell pwd)/../../coregen/"
diff --git a/fpga/usrp2/top/N2x0/Makefile.N210R3 b/fpga/usrp2/top/N2x0/Makefile.N210R3
index 2937dc409..0b53ac951 100644
--- a/fpga/usrp2/top/N2x0/Makefile.N210R3
+++ b/fpga/usrp2/top/N2x0/Makefile.N210R3
@@ -1,5 +1,5 @@
#
-# Copyright 2008 Ettus Research LLC
+# Copyright 2008-2012 Ettus Research LLC
#
##################################################
@@ -8,6 +8,10 @@
TOP_MODULE = u2plus
BUILD_DIR = $(abspath build$(ISE)-N210R3)
+# set me in a custom makefile
+CUSTOM_SRCS =
+CUSTOM_DEFS =
+
##################################################
# Include other makefiles
##################################################
@@ -52,7 +56,8 @@ u2plus.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) $(EXTRAM_SRCS)
+$(VRT_SRCS) $(UDP_SRCS) $(COREGEN_SRCS) $(EXTRAM_SRCS) \
+$(CUSTOM_SRCS)
##################################################
# Process Properties
@@ -65,7 +70,8 @@ SYNTHESIZE_PROPERTIES = \
"Register Balancing" Yes \
"Use Clock Enable" Auto \
"Use Synchronous Reset" Auto \
-"Use Synchronous Set" Auto
+"Use Synchronous Set" Auto \
+"Verilog Macros" "$(CUSTOM_DEFS)"
TRANSLATE_PROPERTIES = \
"Macro Search Path" "$(shell pwd)/../../coregen/"
diff --git a/fpga/usrp2/top/N2x0/Makefile.N210R4 b/fpga/usrp2/top/N2x0/Makefile.N210R4
index 39a2508f9..a7d2a9b49 100644
--- a/fpga/usrp2/top/N2x0/Makefile.N210R4
+++ b/fpga/usrp2/top/N2x0/Makefile.N210R4
@@ -1,5 +1,5 @@
#
-# Copyright 2008 Ettus Research LLC
+# Copyright 2008-2012 Ettus Research LLC
#
##################################################
@@ -8,6 +8,10 @@
TOP_MODULE = u2plus
BUILD_DIR = $(abspath build$(ISE)-N210R4)
+# set me in a custom makefile
+CUSTOM_SRCS =
+CUSTOM_DEFS =
+
##################################################
# Include other makefiles
##################################################
@@ -53,7 +57,8 @@ u2plus.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) $(EXTRAM_SRCS)
+$(VRT_SRCS) $(UDP_SRCS) $(COREGEN_SRCS) $(EXTRAM_SRCS) \
+$(CUSTOM_SRCS)
##################################################
# Process Properties
@@ -67,7 +72,7 @@ SYNTHESIZE_PROPERTIES = \
"Use Clock Enable" Auto \
"Use Synchronous Reset" Auto \
"Use Synchronous Set" Auto \
-"Verilog Macros" "LVDS=1"
+"Verilog Macros" "LVDS=1 $(CUSTOM_DEFS)"
TRANSLATE_PROPERTIES = \
"Macro Search Path" "$(shell pwd)/../../coregen/"
diff --git a/fpga/usrp2/top/N2x0/u2plus_core.v b/fpga/usrp2/top/N2x0/u2plus_core.v
index 3ead0db8e..378f212e4 100644
--- a/fpga/usrp2/top/N2x0/u2plus_core.v
+++ b/fpga/usrp2/top/N2x0/u2plus_core.v
@@ -1,5 +1,5 @@
//
-// Copyright 2011 Ettus Research LLC
+// Copyright 2011-2012 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
@@ -152,7 +152,7 @@ module u2plus_core
localparam SR_SIMTIMER = 8; // 2
localparam SR_TIME64 = 10; // 6
localparam SR_BUF_POOL = 16; // 4
-
+ localparam SR_USER_REGS = 20; // 2
localparam SR_RX_FRONT = 24; // 5
localparam SR_RX_CTRL0 = 32; // 9
localparam SR_RX_DSP0 = 48; // 7
@@ -170,15 +170,16 @@ module u2plus_core
// all (most?) are 36 bits wide, so 9 is 1 BRAM, 10 is 2, 11 is 4 BRAMs
// localparam DSP_TX_FIFOSIZE = 9; unused -- DSPTX uses extram fifo
localparam DSP_RX_FIFOSIZE = 10;
+ localparam DSP_TX_FIFOSIZE = 10;
localparam ETH_TX_FIFOSIZE = 9;
localparam ETH_RX_FIFOSIZE = 11;
localparam SERDES_TX_FIFOSIZE = 9;
localparam SERDES_RX_FIFOSIZE = 9; // RX currently doesn't use a fifo?
-
- wire [7:0] set_addr, set_addr_dsp;
- wire [31:0] set_data, set_data_dsp;
- wire set_stb, set_stb_dsp;
-
+
+ wire [7:0] set_addr, set_addr_dsp, set_addr_user;
+ wire [31:0] set_data, set_data_dsp, set_data_user;
+ wire set_stb, set_stb_dsp, set_stb_user;
+
reg wb_rst;
wire dsp_rst = wb_rst;
@@ -435,7 +436,7 @@ module u2plus_core
// Buffer Pool Status -- Slave #5
//compatibility number -> increment when the fpga has been sufficiently altered
- localparam compat_num = {16'd8, 16'd2}; //major, minor
+ localparam compat_num = {16'd9, 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),
@@ -478,7 +479,13 @@ module u2plus_core
settings_bus_crossclock settings_bus_crossclock
(.clk_i(wb_clk), .rst_i(wb_rst), .set_stb_i(set_stb), .set_addr_i(set_addr), .set_data_i(set_data),
.clk_o(dsp_clk), .rst_o(dsp_rst), .set_stb_o(set_stb_dsp), .set_addr_o(set_addr_dsp), .set_data_o(set_data_dsp));
-
+
+ user_settings #(.BASE(SR_USER_REGS)) user_settings
+ (.clk(dsp_clk),.rst(dsp_rst),.set_stb(set_stb_dsp),
+ .set_addr(set_addr_dsp),.set_data(set_data_dsp),
+ .set_addr_user(set_addr_user),.set_data_user(set_data_user),
+ .set_stb_user(set_stb_user) );
+
// Output control lines
wire [7:0] clock_outs, serdes_outs, adc_outs;
assign {clock_ready, clk_en[1:0], clk_sel[1:0]} = clock_outs[4:0];
@@ -559,68 +566,62 @@ module u2plus_core
// /////////////////////////////////////////////////////////////////////////
// ADC Frontend
- wire [23:0] adc_i, adc_q;
+ wire [23:0] rx_fe_i, rx_fe_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());
+ .i_out(rx_fe_i), .q_out(rx_fe_q), .run(run_rx0_d1 | run_rx1_d1), .debug());
// /////////////////////////////////////////////////////////////////////////
// DSP RX 0
wire [31:0] sample_rx0;
- wire clear_rx0, strobe_rx0;
+ wire strobe_rx0, clear_rx0;
always @(posedge dsp_clk)
run_rx0_d1 <= run_rx0;
- dsp_core_rx #(.BASE(SR_RX_DSP0)) dsp_core_rx0
- (.clk(dsp_clk),.rst(dsp_rst),
+ ddc_chain #(.BASE(SR_RX_DSP0), .DSPNO(0)) ddc_chain0
+ (.clk(dsp_clk), .rst(dsp_rst), .clr(clear_rx0),
.set_stb(set_stb_dsp),.set_addr(set_addr_dsp),.set_data(set_data_dsp),
- .adc_i(adc_i),.adc_ovf_i(adc_ovf_a),.adc_q(adc_q),.adc_ovf_q(adc_ovf_b),
+ .set_stb_user(set_stb_user), .set_addr_user(set_addr_user), .set_data_user(set_data_user),
+ .rx_fe_i(rx_fe_i),.rx_fe_q(rx_fe_q),
.sample(sample_rx0), .run(run_rx0_d1), .strobe(strobe_rx0),
.debug() );
- setting_reg #(.my_addr(SR_RX_CTRL0+3)) sr_clear_rx0
- (.clk(dsp_clk),.rst(dsp_rst),
- .strobe(set_stb_dsp),.addr(set_addr_dsp),.in(set_data_dsp),
- .out(),.changed(clear_rx0));
-
- vita_rx_chain #(.BASE(SR_RX_CTRL0),.UNIT(0),.FIFOSIZE(DSP_RX_FIFOSIZE)) vita_rx_chain0
- (.clk(dsp_clk), .reset(dsp_rst), .clear(clear_rx0),
+ vita_rx_chain #(.BASE(SR_RX_CTRL0),.UNIT(0),.FIFOSIZE(DSP_RX_FIFOSIZE), .DSP_NUMBER(0)) vita_rx_chain0
+ (.clk(dsp_clk), .reset(dsp_rst),
.set_stb(set_stb_dsp),.set_addr(set_addr_dsp),.set_data(set_data_dsp),
+ .set_stb_user(set_stb_user), .set_addr_user(set_addr_user), .set_data_user(set_data_user),
.vita_time(vita_time), .overrun(overrun0),
- .sample(sample_rx0), .run(run_rx0), .strobe(strobe_rx0),
+ .sample(sample_rx0), .run(run_rx0), .strobe(strobe_rx0), .clear_o(clear_rx0),
.rx_data_o(wr1_dat), .rx_src_rdy_o(wr1_ready_i), .rx_dst_rdy_i(wr1_ready_o),
.debug() );
// /////////////////////////////////////////////////////////////////////////
// DSP RX 1
wire [31:0] sample_rx1;
- wire clear_rx1, strobe_rx1;
+ wire strobe_rx1, clear_rx1;
always @(posedge dsp_clk)
run_rx1_d1 <= run_rx1;
- dsp_core_rx #(.BASE(SR_RX_DSP1)) dsp_core_rx1
- (.clk(dsp_clk),.rst(dsp_rst),
+ ddc_chain #(.BASE(SR_RX_DSP1), .DSPNO(1)) ddc_chain1
+ (.clk(dsp_clk), .rst(dsp_rst), .clr(clear_rx1),
.set_stb(set_stb_dsp),.set_addr(set_addr_dsp),.set_data(set_data_dsp),
- .adc_i(adc_i),.adc_ovf_i(adc_ovf_a),.adc_q(adc_q),.adc_ovf_q(adc_ovf_b),
+ .set_stb_user(set_stb_user), .set_addr_user(set_addr_user), .set_data_user(set_data_user),
+ .rx_fe_i(rx_fe_i),.rx_fe_q(rx_fe_q),
.sample(sample_rx1), .run(run_rx1_d1), .strobe(strobe_rx1),
.debug() );
- setting_reg #(.my_addr(SR_RX_CTRL1+3)) sr_clear_rx1
- (.clk(dsp_clk),.rst(dsp_rst),
- .strobe(set_stb_dsp),.addr(set_addr_dsp),.in(set_data_dsp),
- .out(),.changed(clear_rx1));
-
- vita_rx_chain #(.BASE(SR_RX_CTRL1),.UNIT(2),.FIFOSIZE(DSP_RX_FIFOSIZE)) vita_rx_chain1
- (.clk(dsp_clk), .reset(dsp_rst), .clear(clear_rx1),
+ vita_rx_chain #(.BASE(SR_RX_CTRL1),.UNIT(2),.FIFOSIZE(DSP_RX_FIFOSIZE), .DSP_NUMBER(1)) vita_rx_chain1
+ (.clk(dsp_clk), .reset(dsp_rst),
.set_stb(set_stb_dsp),.set_addr(set_addr_dsp),.set_data(set_data_dsp),
+ .set_stb_user(set_stb_user), .set_addr_user(set_addr_user), .set_data_user(set_data_user),
.vita_time(vita_time), .overrun(overrun1),
- .sample(sample_rx1), .run(run_rx1), .strobe(strobe_rx1),
+ .sample(sample_rx1), .run(run_rx1), .strobe(strobe_rx1), .clear_o(clear_rx1),
.rx_data_o(wr3_dat), .rx_src_rdy_o(wr3_ready_i), .rx_dst_rdy_i(wr3_ready_o),
.debug() );
@@ -632,10 +633,6 @@ module u2plus_core
wire [31:0] debug_vt;
wire clear_tx;
- setting_reg #(.my_addr(SR_TX_CTRL+1)) sr_clear_tx
- (.clk(dsp_clk),.rst(dsp_rst),.strobe(set_stb_dsp),.addr(set_addr_dsp),
- .in(set_data_dsp),.out(),.changed(clear_tx));
-
assign RAM_A[20:18] = 3'b0;
ext_fifo #(.EXT_WIDTH(36),.INT_WIDTH(36),.RAM_DEPTH(18),.FIFO_DEPTH(18))
@@ -661,28 +658,39 @@ module u2plus_core
.debug(debug_extfifo),
.debug2(debug_extfifo2) );
- wire [23:0] tx_i, tx_q;
+ wire [23:0] tx_fe_i, tx_fe_q;
+ wire [31:0] sample_tx;
+ wire strobe_tx;
- vita_tx_chain #(.BASE_CTRL(SR_TX_CTRL), .BASE_DSP(SR_TX_DSP),
+ vita_tx_chain #(.BASE(SR_TX_CTRL), .FIFOSIZE(DSP_TX_FIFOSIZE),
.REPORT_ERROR(1), .DO_FLOW_CONTROL(1),
.PROT_ENG_FLAGS(1), .USE_TRANS_HEADER(1),
.DSP_NUMBER(0))
vita_tx_chain
(.clk(dsp_clk), .reset(dsp_rst),
.set_stb(set_stb_dsp),.set_addr(set_addr_dsp),.set_data(set_data_dsp),
+ .set_stb_user(set_stb_user), .set_addr_user(set_addr_user), .set_data_user(set_data_user),
.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),
- .tx_i(tx_i),.tx_q(tx_q),
- .underrun(underrun), .run(run_tx),
+ .sample(sample_tx), .strobe(strobe_tx),
+ .underrun(underrun), .run(run_tx), .clear_o(clear_tx),
.debug(debug_vt));
+ duc_chain #(.BASE(SR_TX_DSP), .DSPNO(0)) duc_chain
+ (.clk(dsp_clk),.rst(dsp_rst), .clr(clear_tx),
+ .set_stb(set_stb_dsp),.set_addr(set_addr_dsp),.set_data(set_data_dsp),
+ .set_stb_user(set_stb_user), .set_addr_user(set_addr_user), .set_data_user(set_data_user),
+ .tx_fe_i(tx_fe_i),.tx_fe_q(tx_fe_q),
+ .sample(sample_tx), .run(run_tx), .strobe(strobe_tx),
+ .debug() );
+
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),
+ .tx_i(tx_fe_i), .tx_q(tx_fe_q), .run(1'b1),
.dac_a(dac_a), .dac_b(dac_b));
-
+
// ///////////////////////////////////////////////////////////////////////////////////
// SERDES
@@ -701,7 +709,7 @@ module u2plus_core
wire [31:0] debug_sync;
- time_64bit #(.TICKS_PER_SEC(32'd100000000),.BASE(SR_TIME64)) time_64bit
+ time_64bit #(.BASE(SR_TIME64)) time_64bit
(.clk(dsp_clk), .rst(dsp_rst), .set_stb(set_stb_dsp), .set_addr(set_addr_dsp), .set_data(set_data_dsp),
.pps(pps_in), .vita_time(vita_time), .vita_time_pps(vita_time_pps), .pps_int(pps_int),
.exp_time_in(exp_time_in), .exp_time_out(exp_time_out), .good_sync(good_sync), .debug(debug_sync));
diff --git a/fpga/usrp2/top/USRP2/Makefile b/fpga/usrp2/top/USRP2/Makefile
index 8ebb43639..1fc375c76 100644
--- a/fpga/usrp2/top/USRP2/Makefile
+++ b/fpga/usrp2/top/USRP2/Makefile
@@ -1,5 +1,5 @@
#
-# Copyright 2008 Ettus Research LLC
+# Copyright 2008-2012 Ettus Research LLC
#
##################################################
@@ -8,6 +8,10 @@
TOP_MODULE = u2_rev3
BUILD_DIR = $(abspath build)
+# set me in a custom makefile
+CUSTOM_SRCS =
+CUSTOM_DEFS =
+
##################################################
# Include other makefiles
##################################################
@@ -52,7 +56,8 @@ u2_rev3.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) $(EXTRAM_SRCS)
+$(VRT_SRCS) $(UDP_SRCS) $(COREGEN_SRCS) $(EXTRAM_SRCS) \
+$(CUSTOM_SRCS)
##################################################
# Process Properties
@@ -65,7 +70,8 @@ SYNTHESIZE_PROPERTIES = \
"Register Balancing" Yes \
"Use Clock Enable" Auto \
"Use Synchronous Reset" Auto \
-"Use Synchronous Set" Auto
+"Use Synchronous Set" Auto \
+"Verilog Macros" "$(CUSTOM_DEFS)"
TRANSLATE_PROPERTIES = \
"Macro Search Path" "$(shell pwd)/../../coregen/"
diff --git a/fpga/usrp2/top/USRP2/u2_core.v b/fpga/usrp2/top/USRP2/u2_core.v
index bbd0e9337..9b26b98e1 100644
--- a/fpga/usrp2/top/USRP2/u2_core.v
+++ b/fpga/usrp2/top/USRP2/u2_core.v
@@ -1,5 +1,5 @@
//
-// Copyright 2011 Ettus Research LLC
+// Copyright 2011-2012 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
@@ -157,7 +157,7 @@ module u2_core
localparam SR_SIMTIMER = 8; // 2
localparam SR_TIME64 = 10; // 6
localparam SR_BUF_POOL = 16; // 4
-
+ localparam SR_USER_REGS = 20; // 2
localparam SR_RX_FRONT = 24; // 5
localparam SR_RX_CTRL0 = 32; // 9
localparam SR_RX_DSP0 = 48; // 7
@@ -175,15 +175,16 @@ module u2_core
// all (most?) are 36 bits wide, so 9 is 1 BRAM, 10 is 2, 11 is 4 BRAMs
// localparam DSP_TX_FIFOSIZE = 9; unused -- DSPTX uses extram fifo
localparam DSP_RX_FIFOSIZE = 10;
+ localparam DSP_TX_FIFOSIZE = 10;
localparam ETH_TX_FIFOSIZE = 9;
localparam ETH_RX_FIFOSIZE = 11;
localparam SERDES_TX_FIFOSIZE = 9;
localparam SERDES_RX_FIFOSIZE = 9; // RX currently doesn't use a fifo?
-
- wire [7:0] set_addr, set_addr_dsp;
- wire [31:0] set_data, set_data_dsp;
- wire set_stb, set_stb_dsp;
-
+
+ wire [7:0] set_addr, set_addr_dsp, set_addr_user;
+ wire [31:0] set_data, set_data_dsp, set_data_user;
+ wire set_stb, set_stb_dsp, set_stb_user;
+
wire ram_loader_done, ram_loader_rst;
wire wb_rst;
wire dsp_rst = wb_rst;
@@ -441,7 +442,7 @@ module u2_core
// Buffer Pool Status -- Slave #5
//compatibility number -> increment when the fpga has been sufficiently altered
- localparam compat_num = {16'd8, 16'd2}; //major, minor
+ localparam compat_num = {16'd9, 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),
@@ -484,7 +485,13 @@ module u2_core
settings_bus_crossclock settings_bus_crossclock
(.clk_i(wb_clk), .rst_i(wb_rst), .set_stb_i(set_stb), .set_addr_i(set_addr), .set_data_i(set_data),
.clk_o(dsp_clk), .rst_o(dsp_rst), .set_stb_o(set_stb_dsp), .set_addr_o(set_addr_dsp), .set_data_o(set_data_dsp));
-
+
+ user_settings #(.BASE(SR_USER_REGS)) user_settings
+ (.clk(dsp_clk),.rst(dsp_rst),.set_stb(set_stb_dsp),
+ .set_addr(set_addr_dsp),.set_data(set_data_dsp),
+ .set_addr_user(set_addr_user),.set_data_user(set_data_user),
+ .set_stb_user(set_stb_user) );
+
// Output control lines
wire [7:0] clock_outs, serdes_outs, adc_outs;
assign {clock_ready, clk_en[1:0], clk_sel[1:0]} = clock_outs[4:0];
@@ -547,68 +554,62 @@ module u2_core
// /////////////////////////////////////////////////////////////////////////
// ADC Frontend
- wire [23:0] adc_i, adc_q;
+ wire [23:0] rx_fe_i, rx_fe_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());
+ .i_out(rx_fe_i), .q_out(rx_fe_q), .run(run_rx0_d1 | run_rx1_d1), .debug());
// /////////////////////////////////////////////////////////////////////////
// DSP RX 0
wire [31:0] sample_rx0;
- wire clear_rx0, strobe_rx0;
+ wire strobe_rx0, clear_rx0;
always @(posedge dsp_clk)
run_rx0_d1 <= run_rx0;
- dsp_core_rx #(.BASE(SR_RX_DSP0)) dsp_core_rx0
- (.clk(dsp_clk),.rst(dsp_rst),
+ ddc_chain #(.BASE(SR_RX_DSP0), .DSPNO(0)) ddc_chain0
+ (.clk(dsp_clk), .rst(dsp_rst), .clr(clear_rx0),
.set_stb(set_stb_dsp),.set_addr(set_addr_dsp),.set_data(set_data_dsp),
- .adc_i(adc_i),.adc_ovf_i(adc_ovf_a),.adc_q(adc_q),.adc_ovf_q(adc_ovf_b),
+ .set_stb_user(set_stb_user), .set_addr_user(set_addr_user), .set_data_user(set_data_user),
+ .rx_fe_i(rx_fe_i),.rx_fe_q(rx_fe_q),
.sample(sample_rx0), .run(run_rx0_d1), .strobe(strobe_rx0),
.debug() );
- setting_reg #(.my_addr(SR_RX_CTRL0+3)) sr_clear_rx0
- (.clk(dsp_clk),.rst(dsp_rst),
- .strobe(set_stb_dsp),.addr(set_addr_dsp),.in(set_data_dsp),
- .out(),.changed(clear_rx0));
-
- vita_rx_chain #(.BASE(SR_RX_CTRL0),.UNIT(0),.FIFOSIZE(DSP_RX_FIFOSIZE)) vita_rx_chain0
- (.clk(dsp_clk), .reset(dsp_rst), .clear(clear_rx0),
+ vita_rx_chain #(.BASE(SR_RX_CTRL0),.UNIT(0),.FIFOSIZE(DSP_RX_FIFOSIZE), .DSP_NUMBER(0)) vita_rx_chain0
+ (.clk(dsp_clk), .reset(dsp_rst),
.set_stb(set_stb_dsp),.set_addr(set_addr_dsp),.set_data(set_data_dsp),
+ .set_stb_user(set_stb_user), .set_addr_user(set_addr_user), .set_data_user(set_data_user),
.vita_time(vita_time), .overrun(overrun0),
- .sample(sample_rx0), .run(run_rx0), .strobe(strobe_rx0),
+ .sample(sample_rx0), .run(run_rx0), .strobe(strobe_rx0), .clear_o(clear_rx0),
.rx_data_o(wr1_dat), .rx_src_rdy_o(wr1_ready_i), .rx_dst_rdy_i(wr1_ready_o),
.debug() );
// /////////////////////////////////////////////////////////////////////////
// DSP RX 1
wire [31:0] sample_rx1;
- wire clear_rx1, strobe_rx1;
+ wire strobe_rx1, clear_rx1;
always @(posedge dsp_clk)
run_rx1_d1 <= run_rx1;
- dsp_core_rx #(.BASE(SR_RX_DSP1)) dsp_core_rx1
- (.clk(dsp_clk),.rst(dsp_rst),
+ ddc_chain #(.BASE(SR_RX_DSP1), .DSPNO(1)) ddc_chain1
+ (.clk(dsp_clk), .rst(dsp_rst), .clr(clear_rx1),
.set_stb(set_stb_dsp),.set_addr(set_addr_dsp),.set_data(set_data_dsp),
- .adc_i(adc_i),.adc_ovf_i(adc_ovf_a),.adc_q(adc_q),.adc_ovf_q(adc_ovf_b),
+ .set_stb_user(set_stb_user), .set_addr_user(set_addr_user), .set_data_user(set_data_user),
+ .rx_fe_i(rx_fe_i),.rx_fe_q(rx_fe_q),
.sample(sample_rx1), .run(run_rx1_d1), .strobe(strobe_rx1),
.debug() );
- setting_reg #(.my_addr(SR_RX_CTRL1+3)) sr_clear_rx1
- (.clk(dsp_clk),.rst(dsp_rst),
- .strobe(set_stb_dsp),.addr(set_addr_dsp),.in(set_data_dsp),
- .out(),.changed(clear_rx1));
-
- vita_rx_chain #(.BASE(SR_RX_CTRL1),.UNIT(2),.FIFOSIZE(DSP_RX_FIFOSIZE)) vita_rx_chain1
- (.clk(dsp_clk), .reset(dsp_rst), .clear(clear_rx1),
+ vita_rx_chain #(.BASE(SR_RX_CTRL1),.UNIT(2),.FIFOSIZE(DSP_RX_FIFOSIZE), .DSP_NUMBER(1)) vita_rx_chain1
+ (.clk(dsp_clk), .reset(dsp_rst),
.set_stb(set_stb_dsp),.set_addr(set_addr_dsp),.set_data(set_data_dsp),
+ .set_stb_user(set_stb_user), .set_addr_user(set_addr_user), .set_data_user(set_data_user),
.vita_time(vita_time), .overrun(overrun1),
- .sample(sample_rx1), .run(run_rx1), .strobe(strobe_rx1),
+ .sample(sample_rx1), .run(run_rx1), .strobe(strobe_rx1), .clear_o(clear_rx1),
.rx_data_o(wr3_dat), .rx_src_rdy_o(wr3_ready_i), .rx_dst_rdy_i(wr3_ready_o),
.debug() );
@@ -620,10 +621,6 @@ module u2_core
wire [31:0] debug_vt;
wire clear_tx;
- setting_reg #(.my_addr(SR_TX_CTRL+1)) sr_clear_tx
- (.clk(dsp_clk),.rst(dsp_rst),.strobe(set_stb_dsp),.addr(set_addr_dsp),
- .in(set_data_dsp),.out(),.changed(clear_tx));
-
ext_fifo #(.EXT_WIDTH(18),.INT_WIDTH(36),.RAM_DEPTH(19),.FIFO_DEPTH(19))
ext_fifo_i1
(.int_clk(dsp_clk),
@@ -647,28 +644,39 @@ module u2_core
.debug(debug_extfifo),
.debug2(debug_extfifo2) );
- wire [23:0] tx_i, tx_q;
+ wire [23:0] tx_fe_i, tx_fe_q;
+ wire [31:0] sample_tx;
+ wire strobe_tx;
- vita_tx_chain #(.BASE_CTRL(SR_TX_CTRL), .BASE_DSP(SR_TX_DSP),
+ vita_tx_chain #(.BASE(SR_TX_CTRL), .FIFOSIZE(DSP_TX_FIFOSIZE),
.REPORT_ERROR(1), .DO_FLOW_CONTROL(1),
.PROT_ENG_FLAGS(1), .USE_TRANS_HEADER(1),
.DSP_NUMBER(0))
vita_tx_chain
(.clk(dsp_clk), .reset(dsp_rst),
.set_stb(set_stb_dsp),.set_addr(set_addr_dsp),.set_data(set_data_dsp),
+ .set_stb_user(set_stb_user), .set_addr_user(set_addr_user), .set_data_user(set_data_user),
.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),
- .tx_i(tx_i),.tx_q(tx_q),
- .underrun(underrun), .run(run_tx),
+ .sample(sample_tx), .strobe(strobe_tx),
+ .underrun(underrun), .run(run_tx), .clear_o(clear_tx),
.debug(debug_vt));
+ duc_chain #(.BASE(SR_TX_DSP), .DSPNO(0)) duc_chain
+ (.clk(dsp_clk),.rst(dsp_rst), .clr(clear_tx),
+ .set_stb(set_stb_dsp),.set_addr(set_addr_dsp),.set_data(set_data_dsp),
+ .set_stb_user(set_stb_user), .set_addr_user(set_addr_user), .set_data_user(set_data_user),
+ .tx_fe_i(tx_fe_i),.tx_fe_q(tx_fe_q),
+ .sample(sample_tx), .run(run_tx), .strobe(strobe_tx),
+ .debug() );
+
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),
+ .tx_i(tx_fe_i), .tx_q(tx_fe_q), .run(1'b1),
.dac_a(dac_a), .dac_b(dac_b));
-
+
// ///////////////////////////////////////////////////////////////////////////////////
// SERDES
@@ -689,7 +697,7 @@ module u2_core
wire [31:0] debug_sync;
- time_64bit #(.TICKS_PER_SEC(32'd100000000),.BASE(SR_TIME64)) time_64bit
+ time_64bit #(.BASE(SR_TIME64)) time_64bit
(.clk(dsp_clk), .rst(dsp_rst), .set_stb(set_stb_dsp), .set_addr(set_addr_dsp), .set_data(set_data_dsp),
.pps(pps_in), .vita_time(vita_time), .vita_time_pps(vita_time_pps), .pps_int(pps_int),
.exp_time_in(exp_time_in), .exp_time_out(exp_time_out), .good_sync(good_sync), .debug(debug_sync));
diff --git a/fpga/usrp2/vrt/Makefile.srcs b/fpga/usrp2/vrt/Makefile.srcs
index 166ed44ef..84ba5dc29 100644
--- a/fpga/usrp2/vrt/Makefile.srcs
+++ b/fpga/usrp2/vrt/Makefile.srcs
@@ -15,4 +15,6 @@ vita_tx_chain.v \
gen_context_pkt.v \
trigger_context_pkt.v \
vita_pkt_gen.v \
+vita_rx_engine_glue.v \
+vita_tx_engine_glue.v \
))
diff --git a/fpga/usrp2/vrt/gen_context_pkt.v b/fpga/usrp2/vrt/gen_context_pkt.v
index bdfca8237..d6674e887 100644
--- a/fpga/usrp2/vrt/gen_context_pkt.v
+++ b/fpga/usrp2/vrt/gen_context_pkt.v
@@ -32,12 +32,11 @@ module gen_context_pkt
localparam CTXT_PROT_ENG = 1;
localparam CTXT_HEADER = 2;
localparam CTXT_STREAMID = 3;
- localparam CTXT_SECS = 4;
- localparam CTXT_TICS = 5;
- localparam CTXT_TICS2 = 6;
- localparam CTXT_MESSAGE = 7;
- localparam CTXT_FLOWCTRL = 8;
- localparam CTXT_DONE = 9;
+ localparam CTXT_TICS = 4;
+ localparam CTXT_TICS2 = 5;
+ localparam CTXT_MESSAGE = 6;
+ localparam CTXT_FLOWCTRL = 7;
+ localparam CTXT_DONE = 8;
reg [33:0] data_int;
wire src_rdy_int, dst_rdy_int;
@@ -88,11 +87,10 @@ module gen_context_pkt
always @*
case(ctxt_state)
- CTXT_PROT_ENG : data_int <= { 2'b01, 13'b0, DSP_NUMBER[0], 1'b1, 1'b1, 16'd28 }; // UDP port 1 or 3
- CTXT_HEADER : data_int <= { 1'b0, (PROT_ENG_FLAGS ? 1'b0 : 1'b1), 12'b010100001101, seqno, 16'd7 };
+ CTXT_PROT_ENG : data_int <= { 2'b01, 13'b0, DSP_NUMBER[0], 1'b1, 1'b1, 16'd24 }; // UDP port 1 or 3
+ CTXT_HEADER : data_int <= { 1'b0, (PROT_ENG_FLAGS ? 1'b0 : 1'b1), 12'b010100000001, seqno, 16'd6 };
CTXT_STREAMID : data_int <= { 2'b00, streamid };
- CTXT_SECS : data_int <= { 2'b00, err_time[63:32] };
- CTXT_TICS : data_int <= { 2'b00, 32'd0 };
+ CTXT_TICS : data_int <= { 2'b00, err_time[63:32] };
CTXT_TICS2 : data_int <= { 2'b00, err_time[31:0] };
CTXT_MESSAGE : data_int <= { 2'b00, message };
CTXT_FLOWCTRL : data_int <= { 2'b10, seqnum };
diff --git a/fpga/usrp2/vrt/vita_rx_chain.v b/fpga/usrp2/vrt/vita_rx_chain.v
index 8b41e5fa8..c57e6cc05 100644
--- a/fpga/usrp2/vrt/vita_rx_chain.v
+++ b/fpga/usrp2/vrt/vita_rx_chain.v
@@ -1,5 +1,5 @@
//
-// Copyright 2011 Ettus Research LLC
+// Copyright 2011-2012 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
@@ -20,21 +20,31 @@ module vita_rx_chain
#(parameter BASE=0,
parameter UNIT=0,
parameter FIFOSIZE=10,
- parameter PROT_ENG_FLAGS=1)
- (input clk, input reset, input clear,
+ parameter PROT_ENG_FLAGS=1,
+ parameter DSP_NUMBER=0)
+ (input clk, input reset,
input set_stb, input [7:0] set_addr, input [31:0] set_data,
- input [63:0] vita_time, output overrun,
- input [31:0] sample, output run, input strobe,
+ input set_stb_user, input [7:0] set_addr_user, input [31:0] set_data_user,
+ input [63:0] vita_time,
+ input [31:0] sample, input strobe,
output [35:0] rx_data_o, output rx_src_rdy_o, input rx_dst_rdy_i,
+ output overrun, output run, output clear_o,
output [31:0] debug );
-
+
wire [100:0] sample_data;
wire sample_dst_rdy, sample_src_rdy;
wire [31:0] vrc_debug, vrf_debug;
wire [35:0] rx_data_int;
wire rx_src_rdy_int, rx_dst_rdy_int;
-
+
+ wire clear;
+ assign clear_o = clear;
+
+ setting_reg #(.my_addr(BASE+3)) sr
+ (.clk(clk),.rst(reset),.strobe(set_stb),.addr(set_addr),
+ .in(set_data),.out(),.changed(clear));
+
vita_rx_control #(.BASE(BASE), .WIDTH(32)) vita_rx_control
(.clk(clk), .reset(reset), .clear(clear),
.set_stb(set_stb),.set_addr(set_addr),.set_data(set_data),
@@ -65,9 +75,10 @@ module vita_rx_chain
.data_i(rx_data_int), .src_rdy_i(rx_src_rdy_int), .dst_rdy_o(rx_dst_rdy_int),
.data_o(rx_data_int2), .src_rdy_o(rx_src_rdy_int2), .dst_rdy_i(rx_dst_rdy_int2));
- dspengine_16to8 #(.BASE(BASE+9), .BUF_SIZE(FIFOSIZE)) dspengine_16to8
- (.clk(clk),.reset(reset),.clear(clear),
- .set_stb(set_stb), .set_addr(set_addr), .set_data(set_data),
+ vita_rx_engine_glue #(.DSPNO(DSP_NUMBER), .MAIN_SETTINGS_BASE(BASE+3), .BUF_SIZE(FIFOSIZE)) dspengine_rx
+ (.clock(clk),.reset(reset),.clear(clear),
+ .set_stb_main(set_stb), .set_addr_main(set_addr), .set_data_main(set_data),
+ .set_stb_user(set_stb_user), .set_addr_user(set_addr_user), .set_data_user(set_data_user),
.access_we(access_we), .access_stb(access_stb), .access_ok(access_ok), .access_done(access_done),
.access_skip_read(access_skip_read), .access_adr(access_adr), .access_len(access_len),
.access_dat_i(buf_to_dsp), .access_dat_o(dsp_to_buf));
diff --git a/fpga/usrp2/vrt/vita_rx_engine_glue.v b/fpga/usrp2/vrt/vita_rx_engine_glue.v
new file mode 100644
index 000000000..56447a7aa
--- /dev/null
+++ b/fpga/usrp2/vrt/vita_rx_engine_glue.v
@@ -0,0 +1,95 @@
+//
+// Copyright 2012 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/>.
+//
+
+//The following module is used to re-write receive packets to the host.
+//This module provides a packet-based ram interface for manipulating packets.
+//By default, this module uses the built-in 16 to 8 bit converter engine.
+
+module vita_rx_engine_glue
+#(
+ //the dsp unit number: 0, 1, 2...
+ parameter DSPNO = 0,
+
+ //buffer size for ram interface engine
+ parameter BUF_SIZE = 10,
+
+ //base address for built-in settings registers used in this module
+ parameter MAIN_SETTINGS_BASE = 0
+)
+(
+ //control signals
+ input clock, input reset, input clear,
+
+ //main settings bus for built-in modules
+ input set_stb_main, input [7:0] set_addr_main, input [31:0] set_data_main,
+
+ //user settings bus, controlled through user setting regs API
+ input set_stb_user, input [7:0] set_addr_user, input [31:0] set_data_user,
+
+ //ram interface for engine
+ output access_we,
+ output access_stb,
+ input access_ok,
+ output access_done,
+ output access_skip_read,
+ output [BUF_SIZE-1:0] access_adr,
+ input [BUF_SIZE-1:0] access_len,
+ output [35:0] access_dat_o,
+ input [35:0] access_dat_i,
+
+ //debug output (optional)
+ output [31:0] debug
+);
+
+ generate
+ if (DSPNO==0) begin
+ `ifndef RX_ENG0_MODULE
+ dspengine_16to8 #(.BASE(MAIN_SETTINGS_BASE), .BUF_SIZE(BUF_SIZE)) dspengine_16to8
+ (.clk(clock),.reset(reset),.clear(clear),
+ .set_stb(set_stb_main), .set_addr(set_addr_main), .set_data(set_data_main),
+ .access_we(access_we), .access_stb(access_stb), .access_ok(access_ok), .access_done(access_done),
+ .access_skip_read(access_skip_read), .access_adr(access_adr), .access_len(access_len),
+ .access_dat_i(access_dat_i), .access_dat_o(access_dat_o));
+ `else
+ `RX_ENG0_MODULE #(.BUF_SIZE(BUF_SIZE)) rx_eng0_custom
+ (.clock(clock),.reset(reset),.clear(clear),
+ .set_stb(set_stb_user), .set_addr(set_addr_user), .set_data(set_data_user),
+ .access_we(access_we), .access_stb(access_stb), .access_ok(access_ok), .access_done(access_done),
+ .access_skip_read(access_skip_read), .access_adr(access_adr), .access_len(access_len),
+ .access_dat_i(access_dat_i), .access_dat_o(access_dat_o));
+ `endif
+ end
+ else begin
+ `ifndef RX_ENG1_MODULE
+ dspengine_16to8 #(.BASE(MAIN_SETTINGS_BASE), .BUF_SIZE(BUF_SIZE)) dspengine_16to8
+ (.clk(clock),.reset(reset),.clear(clear),
+ .set_stb(set_stb_main), .set_addr(set_addr_main), .set_data(set_data_main),
+ .access_we(access_we), .access_stb(access_stb), .access_ok(access_ok), .access_done(access_done),
+ .access_skip_read(access_skip_read), .access_adr(access_adr), .access_len(access_len),
+ .access_dat_i(access_dat_i), .access_dat_o(access_dat_o));
+ `else
+ `RX_ENG1_MODULE #(.BUF_SIZE(BUF_SIZE)) rx_eng1_custom
+ (.clock(clock),.reset(reset),.clear(clear),
+ .set_stb(set_stb_user), .set_addr(set_addr_user), .set_data(set_data_user),
+ .access_we(access_we), .access_stb(access_stb), .access_ok(access_ok), .access_done(access_done),
+ .access_skip_read(access_skip_read), .access_adr(access_adr), .access_len(access_len),
+ .access_dat_i(access_dat_i), .access_dat_o(access_dat_o));
+ `endif
+ end
+ endgenerate
+
+endmodule //vita_rx_engine_glue
diff --git a/fpga/usrp2/vrt/vita_rx_framer.v b/fpga/usrp2/vrt/vita_rx_framer.v
index bd09315bc..514df1151 100644
--- a/fpga/usrp2/vrt/vita_rx_framer.v
+++ b/fpga/usrp2/vrt/vita_rx_framer.v
@@ -1,5 +1,5 @@
//
-// Copyright 2011 Ettus Research LLC
+// Copyright 2011-2012 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
@@ -93,18 +93,16 @@ module vita_rx_framer
localparam VITA_IDLE = 0;
localparam VITA_HEADER = 1;
localparam VITA_STREAMID = 2;
- localparam VITA_SECS = 3;
- localparam VITA_TICS = 4;
- localparam VITA_TICS2 = 5;
- localparam VITA_PAYLOAD = 6;
- localparam VITA_TRAILER = 7;
- localparam VITA_ERR_HEADER = 9; // All ERR at 4'b1000 or'ed with base
- localparam VITA_ERR_STREAMID = 10;
- localparam VITA_ERR_SECS = 11;
- localparam VITA_ERR_TICS = 12;
- localparam VITA_ERR_TICS2 = 13;
- localparam VITA_ERR_PAYLOAD = 14;
- localparam VITA_ERR_TRAILER = 15; // Extension context packets have no trailer
+ localparam VITA_TICS = 3;
+ localparam VITA_TICS2 = 4;
+ localparam VITA_PAYLOAD = 5;
+ localparam VITA_TRAILER = 6;
+ localparam VITA_ERR_HEADER = 7; // All ERR at 4'b1000 or'ed with base
+ localparam VITA_ERR_STREAMID = 8;
+ localparam VITA_ERR_TICS = 9;
+ localparam VITA_ERR_TICS2 = 10;
+ localparam VITA_ERR_PAYLOAD = 11;
+ localparam VITA_ERR_TRAILER = 12; // Extension context packets have no trailer
always @(posedge clk)
if(reset | clear | clear_pkt_count)
@@ -122,17 +120,15 @@ module vita_rx_framer
VITA_HEADER : pkt_fifo_line <= {2'b01,3'b000,vita_header[28],2'b01,vita_header[25:24],
vita_header[23:20],pkt_count[3:0],vita_pkt_len[15:0]};
VITA_STREAMID : pkt_fifo_line <= {2'b00,vita_streamid};
- VITA_SECS : pkt_fifo_line <= {2'b00,vita_time_fifo_o[63:32]};
- VITA_TICS : pkt_fifo_line <= {2'b00,32'd0};
+ VITA_TICS : pkt_fifo_line <= {2'b00,vita_time_fifo_o[63:32]};
VITA_TICS2 : pkt_fifo_line <= {2'b00,vita_time_fifo_o[31:0]};
VITA_PAYLOAD : pkt_fifo_line <= {2'b00,data_fifo_o};
VITA_TRAILER : pkt_fifo_line <= {2'b10,vita_trailer[31:21],1'b1,vita_trailer[19:9],trl_eob,8'd0};
// Error packets are Extension Context packets, which have no trailer
- VITA_ERR_HEADER : pkt_fifo_line <= {2'b01,4'b0101,4'b0000,vita_header[23:20],pkt_count,16'd6};
+ VITA_ERR_HEADER : pkt_fifo_line <= {2'b01,4'b0101,4'b0000,vita_header[23:20],pkt_count,16'd5};
VITA_ERR_STREAMID : pkt_fifo_line <= {2'b00,vita_streamid};
- VITA_ERR_SECS : pkt_fifo_line <= {2'b00,vita_time_fifo_o[63:32]};
- VITA_ERR_TICS : pkt_fifo_line <= {2'b00,32'd0};
+ VITA_ERR_TICS : pkt_fifo_line <= {2'b00,vita_time_fifo_o[63:32]};
VITA_ERR_TICS2 : pkt_fifo_line <= {2'b00,vita_time_fifo_o[31:0]};
VITA_ERR_PAYLOAD : pkt_fifo_line <= {2'b10,27'd0,flags_fifo_o};
//VITA_ERR_TRAILER : pkt_fifo_line <= {2'b11,vita_trailer};
@@ -164,7 +160,7 @@ module vita_rx_framer
if(has_streamid)
vita_state <= VITA_STREAMID;
else
- vita_state <= VITA_SECS;
+ vita_state <= VITA_TICS;
VITA_PAYLOAD :
if(sample_fifo_src_rdy_i)
begin
@@ -194,12 +190,12 @@ module vita_rx_framer
case(vita_state)
VITA_IDLE :
req_write_pkt_fifo <= 0;
- VITA_HEADER, VITA_STREAMID, VITA_SECS, VITA_TICS, VITA_TICS2, VITA_TRAILER :
+ VITA_HEADER, VITA_STREAMID, VITA_TICS, VITA_TICS2, VITA_TRAILER :
req_write_pkt_fifo <= 1;
VITA_PAYLOAD :
// Write if sample ready and no error flags
req_write_pkt_fifo <= (sample_fifo_src_rdy_i & ~|flags_fifo_o[4:1]);
- VITA_ERR_HEADER, VITA_ERR_STREAMID, VITA_ERR_SECS, VITA_ERR_TICS, VITA_ERR_TICS2, VITA_ERR_PAYLOAD :
+ VITA_ERR_HEADER, VITA_ERR_STREAMID, VITA_ERR_TICS, VITA_ERR_TICS2, VITA_ERR_PAYLOAD :
req_write_pkt_fifo <= 1;
default :
req_write_pkt_fifo <= 0;
diff --git a/fpga/usrp2/vrt/vita_tx_chain.v b/fpga/usrp2/vrt/vita_tx_chain.v
index ac9f08fc8..82a43d57a 100644
--- a/fpga/usrp2/vrt/vita_tx_chain.v
+++ b/fpga/usrp2/vrt/vita_tx_chain.v
@@ -1,5 +1,5 @@
//
-// Copyright 2011 Ettus Research LLC
+// Copyright 2011-2012 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
@@ -17,8 +17,9 @@
module vita_tx_chain
- #(parameter BASE_CTRL=0,
- parameter BASE_DSP=0,
+ #(parameter BASE=0,
+ parameter FIFOSIZE=10,
+ parameter POST_ENGINE_FIFOSIZE=10,
parameter REPORT_ERROR=0,
parameter DO_FLOW_CONTROL=0,
parameter PROT_ENG_FLAGS=0,
@@ -26,11 +27,12 @@ module vita_tx_chain
parameter DSP_NUMBER=0)
(input clk, input reset,
input set_stb, input [7:0] set_addr, input [31:0] set_data,
+ input set_stb_user, input [7:0] set_addr_user, input [31:0] set_data_user,
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 [23:0] tx_i, output [23:0] tx_q,
- output underrun, output run,
+ output [31:0] sample, input strobe,
+ output underrun, output run, output clear_o,
output [31:0] debug);
localparam MAXCHAN = 1;
@@ -38,8 +40,6 @@ module vita_tx_chain
wire [FIFOWIDTH-1:0] tx1_data;
wire tx1_src_rdy, tx1_dst_rdy;
- wire clear_vita;
- wire [31:0] sample_tx;
wire [31:0] streamid, message;
wire trigger, sent;
wire [31:0] debug_vtc, debug_vtd, debug_tx_dsp;
@@ -48,61 +48,104 @@ module vita_tx_chain
wire [31:0] error_code;
wire clear_seqnum;
wire [31:0] current_seqnum;
- wire strobe_tx;
-
+
+ wire clear, flush;
+ assign clear_o = clear;
assign underrun = error;
assign message = error_code;
-
- setting_reg #(.my_addr(BASE_CTRL+1)) sr
+
+ setting_reg #(.my_addr(BASE+0), .width(1)) sr
(.clk(clk),.rst(reset),.strobe(set_stb),.addr(set_addr),
- .in(set_data),.out(),.changed(clear_vita));
+ .in(set_data),.out(flush),.changed(clear));
- setting_reg #(.my_addr(BASE_CTRL+2), .at_reset(0)) sr_streamid
+ setting_reg #(.my_addr(BASE+2), .at_reset(0)) sr_streamid
(.clk(clk),.rst(reset),.strobe(set_stb),.addr(set_addr),
.in(set_data),.out(streamid),.changed(clear_seqnum));
- vita_tx_deframer #(.BASE(BASE_CTRL),
+ //flush control - full rate vacuum of input until flush cleared
+ wire tx_dst_rdy_int, tx_src_rdy_int;
+ wire [35:0] tx_data_int;
+ valve36 flusher_valve
+ (.clk(clk), .reset(reset), .clear(clear & flush), .shutoff(flush),
+ .data_i(tx_data_i), .src_rdy_i(tx_src_rdy_i), .dst_rdy_o(tx_dst_rdy_o),
+ .data_o(tx_data_int), .src_rdy_o(tx_src_rdy_int), .dst_rdy_i(tx_dst_rdy_int));
+
+ wire [35:0] tx_data_int1;
+ wire tx_src_rdy_int1, tx_dst_rdy_int1;
+
+ generate
+ if (FIFOSIZE==0) begin
+ assign tx_data_int1 = tx_data_int;
+ assign tx_src_rdy_int1 = tx_src_rdy_int;
+ assign tx_dst_rdy_int = tx_dst_rdy_int1;
+ end
+ else begin
+ wire [FIFOSIZE-1:0] access_adr, access_len;
+ wire access_we, access_stb, access_ok, access_done, access_skip_read;
+ wire [35:0] dsp_to_buf, buf_to_dsp;
+ wire [35:0] tx_data_int0;
+ wire tx_src_rdy_int0, tx_dst_rdy_int0;
+
+ double_buffer #(.BUF_SIZE(FIFOSIZE)) db
+ (.clk(clk),.reset(reset),.clear(clear),
+ .access_we(access_we), .access_stb(access_stb), .access_ok(access_ok), .access_done(access_done),
+ .access_skip_read(access_skip_read), .access_adr(access_adr), .access_len(access_len),
+ .access_dat_i(dsp_to_buf), .access_dat_o(buf_to_dsp),
+
+ .data_i(tx_data_int), .src_rdy_i(tx_src_rdy_int), .dst_rdy_o(tx_dst_rdy_int),
+ .data_o(tx_data_int0), .src_rdy_o(tx_src_rdy_int0), .dst_rdy_i(tx_dst_rdy_int0));
+
+ vita_tx_engine_glue #(.DSPNO(DSP_NUMBER), .MAIN_SETTINGS_BASE(BASE+1), .BUF_SIZE(FIFOSIZE), .HEADER_OFFSET(USE_TRANS_HEADER)) dspengine_tx
+ (.clock(clk),.reset(reset),.clear(clear),
+ .set_stb_main(set_stb), .set_addr_main(set_addr), .set_data_main(set_data),
+ .set_stb_user(set_stb_user), .set_addr_user(set_addr_user), .set_data_user(set_data_user),
+ .access_we(access_we), .access_stb(access_stb), .access_ok(access_ok), .access_done(access_done),
+ .access_skip_read(access_skip_read), .access_adr(access_adr), .access_len(access_len),
+ .access_dat_i(buf_to_dsp), .access_dat_o(dsp_to_buf));
+
+ fifo_cascade #(.WIDTH(36), .SIZE(POST_ENGINE_FIFOSIZE)) post_engine_buffering(
+ .clk(clk), .reset(reset), .clear(clear),
+ .datain(tx_data_int0), .src_rdy_i(tx_src_rdy_int0), .dst_rdy_o(tx_dst_rdy_int0),
+ .dataout(tx_data_int1), .src_rdy_o(tx_src_rdy_int1), .dst_rdy_i(tx_dst_rdy_int1));
+
+ end
+ endgenerate
+
+ vita_tx_deframer #(.BASE(BASE),
.MAXCHAN(MAXCHAN),
.USE_TRANS_HEADER(USE_TRANS_HEADER))
vita_tx_deframer
- (.clk(clk), .reset(reset), .clear(clear_vita), .clear_seqnum(clear_seqnum),
+ (.clk(clk), .reset(reset), .clear(clear), .clear_seqnum(clear_seqnum),
.set_stb(set_stb),.set_addr(set_addr),.set_data(set_data),
- .data_i(tx_data_i), .src_rdy_i(tx_src_rdy_i), .dst_rdy_o(tx_dst_rdy_o),
+ .data_i(tx_data_int1), .src_rdy_i(tx_src_rdy_int1), .dst_rdy_o(tx_dst_rdy_int1),
.sample_fifo_o(tx1_data), .sample_fifo_src_rdy_o(tx1_src_rdy), .sample_fifo_dst_rdy_i(tx1_dst_rdy),
.current_seqnum(current_seqnum),
.debug(debug_vtd) );
- vita_tx_control #(.BASE(BASE_CTRL), .WIDTH(32*MAXCHAN)) vita_tx_control
- (.clk(clk), .reset(reset), .clear(clear_vita),
+ vita_tx_control #(.BASE(BASE), .WIDTH(32*MAXCHAN)) vita_tx_control
+ (.clk(clk), .reset(reset), .clear(clear),
.set_stb(set_stb),.set_addr(set_addr),.set_data(set_data),
.vita_time(vita_time), .error(error), .ack(ack), .error_code(error_code),
.sample_fifo_i(tx1_data), .sample_fifo_src_rdy_i(tx1_src_rdy), .sample_fifo_dst_rdy_o(tx1_dst_rdy),
- .sample(sample_tx), .run(run), .strobe(strobe_tx), .packet_consumed(packet_consumed),
+ .sample(sample), .run(run), .strobe(strobe), .packet_consumed(packet_consumed),
.debug(debug_vtc) );
-
- dsp_core_tx #(.BASE(BASE_DSP)) dsp_core_tx
- (.clk(clk),.rst(reset),
- .set_stb(set_stb),.set_addr(set_addr),.set_data(set_data),
- .sample(sample_tx), .run(run), .strobe(strobe_tx),
- .tx_i(tx_i),.tx_q(tx_q),
- .debug(debug_tx_dsp) );
wire [35:0] flow_data, err_data_int;
wire flow_src_rdy, flow_dst_rdy, err_src_rdy_int, err_dst_rdy_int;
gen_context_pkt #(.PROT_ENG_FLAGS(PROT_ENG_FLAGS),.DSP_NUMBER(DSP_NUMBER)) gen_flow_pkt
- (.clk(clk), .reset(reset), .clear(clear_vita),
+ (.clk(clk), .reset(reset), .clear(clear),
.trigger(trigger & (DO_FLOW_CONTROL==1)), .sent(),
.streamid(streamid), .vita_time(vita_time), .message(32'd0),
.seqnum(current_seqnum),
.data_o(flow_data), .src_rdy_o(flow_src_rdy), .dst_rdy_i(flow_dst_rdy));
- trigger_context_pkt #(.BASE(BASE_CTRL)) trigger_context_pkt
- (.clk(clk), .reset(reset), .clear(clear_vita),
+ trigger_context_pkt #(.BASE(BASE)) trigger_context_pkt
+ (.clk(clk), .reset(reset), .clear(clear),
.set_stb(set_stb),.set_addr(set_addr),.set_data(set_data),
.packet_consumed(packet_consumed), .trigger(trigger));
gen_context_pkt #(.PROT_ENG_FLAGS(PROT_ENG_FLAGS),.DSP_NUMBER(DSP_NUMBER)) gen_tx_err_pkt
- (.clk(clk), .reset(reset), .clear(clear_vita),
+ (.clk(clk), .reset(reset), .clear(clear),
.trigger((error|ack) & (REPORT_ERROR==1)), .sent(),
.streamid(streamid), .vita_time(vita_time), .message(message),
.seqnum(current_seqnum),
diff --git a/fpga/usrp2/vrt/vita_tx_control.v b/fpga/usrp2/vrt/vita_tx_control.v
index 5df89bdbe..c3ce2b96a 100644
--- a/fpga/usrp2/vrt/vita_tx_control.v
+++ b/fpga/usrp2/vrt/vita_tx_control.v
@@ -50,11 +50,9 @@ module vita_tx_control
wire now, early, late, too_early;
- // FIXME ignore too_early for now for timing reasons
- assign too_early = 0;
time_compare
time_compare (.time_now(vita_time), .trigger_time(send_time),
- .now(now), .early(early), .late(late), .too_early());
+ .now(now), .early(early), .late(late), .too_early(too_early));
reg late_qual, late_del;
@@ -187,8 +185,17 @@ module vita_tx_control
assign sample_fifo_dst_rdy_o = (ibs_state == IBS_ERROR) | (strobe & (ibs_state == IBS_RUN)); // FIXME also cleanout
- assign sample = (ibs_state == IBS_RUN) ? sample_fifo_i[5+64+16+WIDTH-1:5+64+16] : {WIDTH{1'b0}};
- //assign run = (ibs_state == IBS_RUN) | (ibs_state == IBS_CONT_BURST);
+ //register the output sample
+ reg [31:0] sample_held;
+ assign sample = sample_held;
+ always @(posedge clk)
+ if(reset | clear)
+ sample_held <= 0;
+ else if (~run)
+ sample_held <= 0;
+ else if (strobe)
+ sample_held <= sample_fifo_i[5+64+16+WIDTH-1:5+64+16];
+
assign error = send_error;
assign ack = send_ack;
diff --git a/fpga/usrp2/vrt/vita_tx_deframer.v b/fpga/usrp2/vrt/vita_tx_deframer.v
index 06ca27767..6919da11a 100644
--- a/fpga/usrp2/vrt/vita_tx_deframer.v
+++ b/fpga/usrp2/vrt/vita_tx_deframer.v
@@ -1,5 +1,5 @@
//
-// Copyright 2011 Ettus Research LLC
+// Copyright 2011-2012 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
@@ -85,7 +85,6 @@ module vita_tx_deframer
localparam VITA_TICS = 6;
localparam VITA_TICS2 = 7;
localparam VITA_PAYLOAD = 8;
- localparam VITA_STORE = 9;
localparam VITA_TRAILER = 10;
localparam VITA_DUMP = 11;
@@ -118,21 +117,7 @@ module vita_tx_deframer
<= 0;
seqnum_err <= 0;
end
- else
- if((vita_state == VITA_STORE) & fifo_space)
- if(vita_eof)
- if(eof)
- vita_state <= (USE_TRANS_HEADER==1) ? VITA_TRANS_HEADER : VITA_HEADER;
- else if(has_trailer_reg)
- vita_state <= VITA_TRAILER;
- else
- vita_state <= VITA_DUMP;
- else
- begin
- vita_state <= VITA_PAYLOAD;
- pkt_len <= pkt_len - 1;
- end
- else if(src_rdy_i)
+ else if(src_rdy_i & dst_rdy_o) begin //valid read
case(vita_state)
VITA_TRANS_HEADER :
begin
@@ -184,14 +169,33 @@ module vita_tx_deframer
vita_state <= VITA_TICS2;
VITA_TICS2 :
vita_state <= VITA_PAYLOAD;
- VITA_PAYLOAD :
- if(line_done)
- begin
- vector_phase <= 0;
- vita_state <= VITA_STORE;
- end
- else
- vector_phase <= vector_phase + 1;
+
+ VITA_PAYLOAD : begin
+
+ //step through each element until line done, then reset
+ vector_phase <= (line_done)? 0: vector_phase + 1;
+
+ //decrement the packet count after each line
+ pkt_len <= (line_done)? pkt_len - 1 : pkt_len;
+
+ //end of frame reached, determine next state
+ //otherwise, keep processing through the payload
+ if (line_done && vita_eof) begin
+
+ if (eof) begin
+ vita_state <= (USE_TRANS_HEADER==1) ? VITA_TRANS_HEADER : VITA_HEADER;
+ end
+ else if (has_trailer_reg) begin
+ vita_state <= VITA_TRAILER;
+ end
+ else begin
+ vita_state <= VITA_DUMP;
+ end
+
+ end //line_done && vita_eof
+
+ end //end VITA_PAYLOAD
+
VITA_TRAILER :
if(eof)
vita_state <= (USE_TRANS_HEADER==1) ? VITA_TRANS_HEADER : VITA_HEADER;
@@ -200,46 +204,53 @@ module vita_tx_deframer
VITA_DUMP :
if(eof)
vita_state <= (USE_TRANS_HEADER==1) ? VITA_TRANS_HEADER : VITA_HEADER;
- VITA_STORE :
- ;
default :
vita_state <= (USE_TRANS_HEADER==1) ? VITA_TRANS_HEADER : VITA_HEADER;
endcase // case (vita_state)
- assign line_done = (vector_phase == numchan);
+ end //valid read
+
+ assign line_done = (MAXCHAN == 1)? 1 : (vector_phase == numchan);
wire [FIFOWIDTH-1:0] fifo_i;
reg [63:0] send_time;
- reg [31:0] sample_a, sample_b, sample_c, sample_d;
always @(posedge clk)
case(vita_state)
- VITA_SECS :
+ VITA_TICS :
send_time[63:32] <= data_i[31:0];
VITA_TICS2 :
send_time[31:0] <= data_i[31:0];
endcase // case (vita_state)
-
+
+ //sample registers for de-framing a vector input
+ reg [31:0] sample_reg [1:0];
always @(posedge clk)
- if(vita_state == VITA_PAYLOAD)
- case(vector_phase)
- 0: sample_a <= data_i[31:0];
- 1: sample_b <= data_i[31:0];
- 2: sample_c <= data_i[31:0];
- 3: sample_d <= data_i[31:0];
- endcase // case (vector_phase)
-
- wire store = (vita_state == VITA_STORE);
+ if(src_rdy_i && dst_rdy_o)
+ sample_reg[vector_phase] <= data_i[31:0];
+
+ wire store = (vita_state == VITA_PAYLOAD)? (src_rdy_i && line_done) : 0;
+ assign dst_rdy_o = (vita_state == VITA_PAYLOAD)? fifo_space : 1;
+
fifo_short #(.WIDTH(FIFOWIDTH)) short_tx_q
(.clk(clk), .reset(reset), .clear(clear),
.datain(fifo_i), .src_rdy_i(store), .dst_rdy_o(fifo_space),
.dataout(sample_fifo_o), .src_rdy_o(sample_fifo_src_rdy_o), .dst_rdy_i(sample_fifo_dst_rdy_i) );
- // sob, eob, has_secs (send_at) ignored on all lines except first
- assign fifo_i = {sample_d,sample_c,sample_b,sample_a,seqnum_err,has_secs_reg,is_sob_reg,is_eob_reg,eop,
- 12'd0,seqnum_reg[3:0],send_time};
+ //assign registered/live data to the samples vector
+ //the numchan'th sample vector is muxed to live data
+ wire [(32*MAXCHAN)-1:0] samples;
+ generate
+ genvar i;
+ for (i=0; i < MAXCHAN; i = i +1) begin : assign_samples
+ wire live_data = (i == (MAXCHAN-1))? 1 : numchan == i;
+ assign samples[32*i + 31:32*i] = (live_data)? data_i[31:0] : sample_reg[i];
+ end
+ endgenerate
- assign dst_rdy_o = ~(vita_state == VITA_PAYLOAD) & ~((vita_state==VITA_STORE)& ~fifo_space) ;
+ // sob, eob, has_tics (send_at) ignored on all lines except first
+ assign fifo_i = {samples,seqnum_err,has_tics_reg,is_sob_reg,is_eob_reg,eop,
+ 12'd0,seqnum_reg[3:0],send_time};
assign debug = { { 8'b0 },
{ 8'b0 },
diff --git a/fpga/usrp2/vrt/vita_tx_engine_glue.v b/fpga/usrp2/vrt/vita_tx_engine_glue.v
new file mode 100644
index 000000000..db0d55dee
--- /dev/null
+++ b/fpga/usrp2/vrt/vita_tx_engine_glue.v
@@ -0,0 +1,99 @@
+//
+// Copyright 2012 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/>.
+//
+
+//The following module is used to re-write transmit packets from the host.
+//This module provides a packet-based ram interface for manipulating packets.
+//By default, this module uses the built-in 8 to 16 bit converter engine.
+
+module vita_tx_engine_glue
+#(
+ //the dsp unit number: 0, 1, 2...
+ parameter DSPNO = 0,
+
+ //buffer size for ram interface engine
+ parameter BUF_SIZE = 10,
+
+ //base address for built-in settings registers used in this module
+ parameter MAIN_SETTINGS_BASE = 0,
+
+ //the number of 32bit lines between start of buffer and vita header
+ //the metadata before the header should be preserved by the engine
+ parameter HEADER_OFFSET = 0
+)
+(
+ //control signals
+ input clock, input reset, input clear,
+
+ //main settings bus for built-in modules
+ input set_stb_main, input [7:0] set_addr_main, input [31:0] set_data_main,
+
+ //user settings bus, controlled through user setting regs API
+ input set_stb_user, input [7:0] set_addr_user, input [31:0] set_data_user,
+
+ //ram interface for engine
+ output access_we,
+ output access_stb,
+ input access_ok,
+ output access_done,
+ output access_skip_read,
+ output [BUF_SIZE-1:0] access_adr,
+ input [BUF_SIZE-1:0] access_len,
+ output [35:0] access_dat_o,
+ input [35:0] access_dat_i,
+
+ //debug output (optional)
+ output [31:0] debug
+);
+
+ generate
+ if (DSPNO==0) begin
+ `ifndef TX_ENG0_MODULE
+ dspengine_8to16 #(.BASE(MAIN_SETTINGS_BASE), .BUF_SIZE(BUF_SIZE), .HEADER_OFFSET(HEADER_OFFSET)) dspengine_8to16
+ (.clk(clock),.reset(reset),.clear(clear),
+ .set_stb(set_stb_main), .set_addr(set_addr_main), .set_data(set_data_main),
+ .access_we(access_we), .access_stb(access_stb), .access_ok(access_ok), .access_done(access_done),
+ .access_skip_read(access_skip_read), .access_adr(access_adr), .access_len(access_len),
+ .access_dat_i(access_dat_i), .access_dat_o(access_dat_o));
+ `else
+ `TX_ENG0_MODULE #(.BUF_SIZE(BUF_SIZE), .HEADER_OFFSET(HEADER_OFFSET)) tx_eng0_custom
+ (.clock(clock),.reset(reset),.clear(clear),
+ .set_stb(set_stb_user), .set_addr(set_addr_user), .set_data(set_data_user),
+ .access_we(access_we), .access_stb(access_stb), .access_ok(access_ok), .access_done(access_done),
+ .access_skip_read(access_skip_read), .access_adr(access_adr), .access_len(access_len),
+ .access_dat_i(access_dat_i), .access_dat_o(access_dat_o));
+ `endif
+ end
+ else begin
+ `ifndef TX_ENG1_MODULE
+ dspengine_8to16 #(.BASE(MAIN_SETTINGS_BASE), .BUF_SIZE(BUF_SIZE), .HEADER_OFFSET(HEADER_OFFSET)) dspengine_8to16
+ (.clk(clock),.reset(reset),.clear(clear),
+ .set_stb(set_stb_main), .set_addr(set_addr_main), .set_data(set_data_main),
+ .access_we(access_we), .access_stb(access_stb), .access_ok(access_ok), .access_done(access_done),
+ .access_skip_read(access_skip_read), .access_adr(access_adr), .access_len(access_len),
+ .access_dat_i(access_dat_i), .access_dat_o(access_dat_o));
+ `else
+ `TX_ENG1_MODULE #(.BUF_SIZE(BUF_SIZE), .HEADER_OFFSET(HEADER_OFFSET)) tx_eng1_custom
+ (.clock(clock),.reset(reset),.clear(clear),
+ .set_stb(set_stb_user), .set_addr(set_addr_user), .set_data(set_data_user),
+ .access_we(access_we), .access_stb(access_stb), .access_ok(access_ok), .access_done(access_done),
+ .access_skip_read(access_skip_read), .access_adr(access_adr), .access_len(access_len),
+ .access_dat_i(access_dat_i), .access_dat_o(access_dat_o));
+ `endif
+ end
+ endgenerate
+
+endmodule //vita_tx_engine_glue
diff --git a/host/examples/benchmark_rate.cpp b/host/examples/benchmark_rate.cpp
index fce184514..8f00e25de 100644
--- a/host/examples/benchmark_rate.cpp
+++ b/host/examples/benchmark_rate.cpp
@@ -40,11 +40,11 @@ unsigned long long num_seq_errors = 0;
/***********************************************************************
* Benchmark RX Rate
**********************************************************************/
-void benchmark_rx_rate(uhd::usrp::multi_usrp::sptr usrp){
+void benchmark_rx_rate(uhd::usrp::multi_usrp::sptr usrp, const std::string &rx_otw){
uhd::set_thread_priority_safe();
//create a receive streamer
- uhd::stream_args_t stream_args("fc32"); //complex floats
+ uhd::stream_args_t stream_args("fc32", rx_otw); //complex floats
uhd::rx_streamer::sptr rx_stream = usrp->get_rx_stream(stream_args);
//print pre-test summary
@@ -94,11 +94,11 @@ void benchmark_rx_rate(uhd::usrp::multi_usrp::sptr usrp){
/***********************************************************************
* Benchmark TX Rate
**********************************************************************/
-void benchmark_tx_rate(uhd::usrp::multi_usrp::sptr usrp){
+void benchmark_tx_rate(uhd::usrp::multi_usrp::sptr usrp, const std::string &tx_otw){
uhd::set_thread_priority_safe();
//create a transmit streamer
- uhd::stream_args_t stream_args("fc32"); //complex floats
+ uhd::stream_args_t stream_args("fc32", tx_otw); //complex floats
uhd::tx_streamer::sptr tx_stream = usrp->get_tx_stream(stream_args);
//print pre-test summary
@@ -162,6 +162,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
std::string args;
double duration;
double rx_rate, tx_rate;
+ std::string rx_otw, tx_otw;
//setup the program options
po::options_description desc("Allowed options");
@@ -171,6 +172,8 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
("duration", po::value<double>(&duration)->default_value(10.0), "duration for the test in seconds")
("rx_rate", po::value<double>(&rx_rate), "specify to perform a RX rate test (sps)")
("tx_rate", po::value<double>(&tx_rate), "specify to perform a TX rate test (sps)")
+ ("rx_otw", po::value<std::string>(&rx_otw)->default_value("sc16"), "specify the over-the-wire sample mode for RX")
+ ("tx_otw", po::value<std::string>(&tx_otw)->default_value("sc16"), "specify the over-the-wire sample mode for TX")
;
po::variables_map vm;
po::store(po::parse_command_line(argc, argv, desc), vm);
@@ -203,13 +206,13 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
//spawn the receive test thread
if (vm.count("rx_rate")){
usrp->set_rx_rate(rx_rate);
- thread_group.create_thread(boost::bind(&benchmark_rx_rate, usrp));
+ thread_group.create_thread(boost::bind(&benchmark_rx_rate, usrp, rx_otw));
}
//spawn the transmit test thread
if (vm.count("tx_rate")){
usrp->set_tx_rate(tx_rate);
- thread_group.create_thread(boost::bind(&benchmark_tx_rate, usrp));
+ thread_group.create_thread(boost::bind(&benchmark_tx_rate, usrp, tx_otw));
thread_group.create_thread(boost::bind(&benchmark_tx_rate_async_helper, usrp));
}
diff --git a/host/examples/test_messages.cpp b/host/examples/test_messages.cpp
index f24a172d1..afb092092 100644
--- a/host/examples/test_messages.cpp
+++ b/host/examples/test_messages.cpp
@@ -26,6 +26,7 @@
#include <boost/bind.hpp>
#include <boost/format.hpp>
#include <cstdlib>
+#include <ctime>
#include <complex>
#include <iostream>
@@ -326,7 +327,7 @@ 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());
+ std::srand((unsigned int) time(NULL));
for (size_t n = 0; n < ntests; n++){
std::string key = tests.keys()[std::rand() % tests.size()];
bool pass = tests[key](usrp, rx_stream, tx_stream);
diff --git a/host/examples/tx_waveforms.cpp b/host/examples/tx_waveforms.cpp
index 39f70aec6..6a377fdac 100644
--- a/host/examples/tx_waveforms.cpp
+++ b/host/examples/tx_waveforms.cpp
@@ -90,7 +90,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
uhd::set_thread_priority_safe();
//variables to be set by po
- std::string args, wave_type, ant, subdev, ref;
+ std::string args, wave_type, ant, subdev, ref, otw;
size_t spb;
double rate, freq, gain, wave_freq, bw;
float ampl;
@@ -111,6 +111,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
("wave-type", po::value<std::string>(&wave_type)->default_value("CONST"), "waveform type (CONST, SQUARE, RAMP, SINE)")
("wave-freq", po::value<double>(&wave_freq)->default_value(0), "waveform frequency in Hz")
("ref", po::value<std::string>(&ref)->default_value("internal"), "clock reference (internal, external, mimo)")
+ ("otw", po::value<std::string>(&otw)->default_value("sc16"), "specify the over-the-wire sample mode")
;
po::variables_map vm;
po::store(po::parse_command_line(argc, argv, desc), vm);
@@ -193,7 +194,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
//create a transmit streamer
//linearly map channels (index0 = channel0, index1 = channel1, ...)
- uhd::stream_args_t stream_args("fc32");
+ uhd::stream_args_t stream_args("fc32", otw);
for (size_t chan = 0; chan < usrp->get_tx_num_channels(); chan++)
stream_args.channels.push_back(chan); //linear mapping
uhd::tx_streamer::sptr tx_stream = usrp->get_tx_stream(stream_args);
diff --git a/host/include/uhd/stream.hpp b/host/include/uhd/stream.hpp
index 352f63e4e..cec2eee79 100644
--- a/host/include/uhd/stream.hpp
+++ b/host/include/uhd/stream.hpp
@@ -79,9 +79,11 @@ struct UHD_API stream_args_t{
* The args parameter is used to pass arbitrary key/value pairs.
* Possible keys used by args (depends on implementation):
*
- * - scalar: an integer scaling factor used with the sc8 wire format.
- * The key/value pair scalar=1024 means that the sample in the DSP
- * was multiplied by 1024 before its upper 8 bits were harvested.
+ * - peak: specifies a fractional sample level to calculate scaling with the sc8 wire format.
+ * When using sc8 samples over the wire, the device must scale samples
+ * (both on the host and in the device) to satisfy the dynamic range needs.
+ * The peak value specifies a fraction of the maximum sample level (1.0 = 100%).
+ * Set peak to max_sample_level/full_scale_level to ensure optimum dynamic range.
*
* - underflow_policy: how the TX DSP should recover from underflow.
* Possible options are "next_burst" or "next_packet".
diff --git a/host/include/uhd/types/metadata.hpp b/host/include/uhd/types/metadata.hpp
index 269c77c7c..788999900 100644
--- a/host/include/uhd/types/metadata.hpp
+++ b/host/include/uhd/types/metadata.hpp
@@ -1,5 +1,5 @@
//
-// Copyright 2010 Ettus Research LLC
+// Copyright 2010-2012 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
@@ -20,6 +20,7 @@
#include <uhd/config.hpp>
#include <uhd/types/time_spec.hpp>
+#include <boost/cstdint.hpp>
namespace uhd{
@@ -140,13 +141,21 @@ namespace uhd{
EVENT_CODE_UNDERFLOW = 0x2,
//! Packet loss between host and device.
EVENT_CODE_SEQ_ERROR = 0x4,
- //! Packet had time that was late (or too early).
+ //! Packet had time that was late.
EVENT_CODE_TIME_ERROR = 0x8,
//! Underflow occurred inside a packet.
EVENT_CODE_UNDERFLOW_IN_PACKET = 0x10,
//! Packet loss within a burst.
- EVENT_CODE_SEQ_ERROR_IN_BURST = 0x20
+ EVENT_CODE_SEQ_ERROR_IN_BURST = 0x20,
+ //! Some kind of custom user payload
+ EVENT_CODE_USER_PAYLOAD = 0x40
} event_code;
+
+ /*!
+ * A special payload populated by custom FPGA fabric.
+ */
+ boost::uint32_t user_payload[4];
+
};
} //namespace uhd
diff --git a/host/include/uhd/types/time_spec.hpp b/host/include/uhd/types/time_spec.hpp
index 02de20ea1..e7d7d5ab4 100644
--- a/host/include/uhd/types/time_spec.hpp
+++ b/host/include/uhd/types/time_spec.hpp
@@ -1,5 +1,5 @@
//
-// Copyright 2010-2011 Ettus Research LLC
+// Copyright 2010-2012 Ettus Research LLC
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -60,7 +60,7 @@ namespace uhd{
time_spec_t(time_t full_secs, double frac_secs = 0);
/*!
- * Create a time_spec_t from whole and fractional seconds.
+ * Create a time_spec_t from whole seconds and fractional ticks.
* Translation from clock-domain specific units.
* \param full_secs the whole/integer seconds count
* \param tick_count the fractional seconds tick count
@@ -69,6 +69,14 @@ namespace uhd{
time_spec_t(time_t full_secs, long tick_count, double tick_rate);
/*!
+ * Create a time_spec_t from a 64-bit tick count.
+ * Translation from clock-domain specific units.
+ * \param ticks an integer count of ticks
+ * \param tick_rate the number of ticks per second
+ */
+ static time_spec_t from_ticks(long long ticks, double tick_rate);
+
+ /*!
* Convert the fractional seconds to clock ticks.
* Translation into clock-domain specific units.
* \param tick_rate the number of ticks per second
@@ -77,6 +85,14 @@ namespace uhd{
long get_tick_count(double tick_rate) const;
/*!
+ * Convert the time spec into a 64-bit tick count.
+ * Translation into clock-domain specific units.
+ * \param tick_rate the number of ticks per second
+ * \return an integer number of ticks
+ */
+ long long to_ticks(const double tick_rate) const;
+
+ /*!
* Get the time as a real-valued seconds count.
* Note: If this time_spec_t represents an absolute time,
* the precision of the fractional seconds may be lost.
@@ -112,6 +128,14 @@ namespace uhd{
//! Implement less_than_comparable interface
UHD_API bool operator<(const time_spec_t &, const time_spec_t &);
+ UHD_INLINE time_t time_spec_t::get_full_secs(void) const{
+ return this->_full_secs;
+ }
+
+ UHD_INLINE double time_spec_t::get_frac_secs(void) const{
+ return this->_frac_secs;
+ }
+
} //namespace uhd
#endif /* INCLUDED_UHD_TYPES_TIME_SPEC_HPP */
diff --git a/host/include/uhd/usrp/multi_usrp.hpp b/host/include/uhd/usrp/multi_usrp.hpp
index 49354f1af..88affa40c 100644
--- a/host/include/uhd/usrp/multi_usrp.hpp
+++ b/host/include/uhd/usrp/multi_usrp.hpp
@@ -24,6 +24,7 @@
#define UHD_USRP_MULTI_USRP_FRONTEND_CAL_API
#define UHD_USRP_MULTI_USRP_COMMAND_TIME_API
#define UHD_USRP_MULTI_USRP_BW_RANGE_API
+#define UHD_USRP_MULTI_USRP_USER_REGS_API
#include <uhd/config.hpp>
#include <uhd/device.hpp>
@@ -338,6 +339,15 @@ public:
*/
virtual std::vector<std::string> get_mboard_sensor_names(size_t mboard = 0) = 0;
+ /*!
+ * Perform write on the user configuration register bus. These only exist if
+ * the user has implemented custom setting registers in the device FPGA.
+ * \param addr 8-bit register address
+ * \param data 32-bit register value
+ * \param mboard which motherboard to set the user register
+ */
+ virtual void set_user_register(const boost::uint8_t addr, const boost::uint32_t data, size_t mboard = ALL_MBOARDS) = 0;
+
/*******************************************************************
* RX methods
******************************************************************/
diff --git a/host/lib/convert/CMakeLists.txt b/host/lib/convert/CMakeLists.txt
index 98907dc29..c42a0a434 100644
--- a/host/lib/convert/CMakeLists.txt
+++ b/host/lib/convert/CMakeLists.txt
@@ -1,5 +1,5 @@
#
-# Copyright 2011 Ettus Research LLC
+# Copyright 2011-2012 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
@@ -73,6 +73,8 @@ IF(HAVE_EMMINTRIN_H)
SET(convert_with_sse2_sources
${CMAKE_CURRENT_SOURCE_DIR}/convert_fc32_with_sse2.cpp
${CMAKE_CURRENT_SOURCE_DIR}/convert_fc64_with_sse2.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/convert_fc32_to_sc8_with_sse2.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/convert_fc64_to_sc8_with_sse2.cpp
)
SET_SOURCE_FILES_PROPERTIES(
${convert_with_sse2_sources}
diff --git a/host/lib/convert/convert_common.hpp b/host/lib/convert/convert_common.hpp
index 699d6301b..55bc2e99d 100644
--- a/host/lib/convert/convert_common.hpp
+++ b/host/lib/convert/convert_common.hpp
@@ -1,5 +1,5 @@
//
-// Copyright 2011 Ettus Research LLC
+// Copyright 2011-2012 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
@@ -190,4 +190,52 @@ static UHD_INLINE void item32_sc8_to_fc64(item32_t item, fc64_t &out0, fc64_t &o
);
}
+/***********************************************************************
+ * Convert complex char to items32 sc8 buffer
+ **********************************************************************/
+static UHD_INLINE item32_t sc8_to_item32_sc8(sc8_t in0, sc8_t in1, double){
+ return
+ (item32_t(boost::uint8_t(in0.real())) << 8) |
+ (item32_t(boost::uint8_t(in0.imag())) << 0) |
+ (item32_t(boost::uint8_t(in1.real())) << 24) |
+ (item32_t(boost::uint8_t(in1.imag())) << 16)
+ ;
+}
+
+/***********************************************************************
+ * Convert complex short to items32 sc8 buffer
+ **********************************************************************/
+static UHD_INLINE item32_t sc16_to_item32_sc8(sc16_t in0, sc16_t in1, double){
+ return
+ (item32_t(boost::uint8_t(in0.real())) << 8) |
+ (item32_t(boost::uint8_t(in0.imag())) << 0) |
+ (item32_t(boost::uint8_t(in1.real())) << 24) |
+ (item32_t(boost::uint8_t(in1.imag())) << 16)
+ ;
+}
+
+/***********************************************************************
+ * Convert complex float to items32 sc8 buffer
+ **********************************************************************/
+static UHD_INLINE item32_t fc32_to_item32_sc8(fc32_t in0, fc32_t in1, double scale_factor){
+ return
+ (item32_t(boost::uint8_t(in0.real()*float(scale_factor))) << 8) |
+ (item32_t(boost::uint8_t(in0.imag()*float(scale_factor))) << 0) |
+ (item32_t(boost::uint8_t(in1.real()*float(scale_factor))) << 24) |
+ (item32_t(boost::uint8_t(in1.imag()*float(scale_factor))) << 16)
+ ;
+}
+
+/***********************************************************************
+ * Convert complex double to items32 sc8 buffer
+ **********************************************************************/
+static UHD_INLINE item32_t fc64_to_item32_sc8(fc64_t in0, fc64_t in1, double scale_factor){
+ return
+ (item32_t(boost::uint8_t(in0.real()*(scale_factor))) << 8) |
+ (item32_t(boost::uint8_t(in0.imag()*(scale_factor))) << 0) |
+ (item32_t(boost::uint8_t(in1.real()*(scale_factor))) << 24) |
+ (item32_t(boost::uint8_t(in1.imag()*(scale_factor))) << 16)
+ ;
+}
+
#endif /* INCLUDED_LIBUHD_CONVERT_COMMON_HPP */
diff --git a/host/lib/convert/convert_fc32_to_sc8_with_sse2.cpp b/host/lib/convert/convert_fc32_to_sc8_with_sse2.cpp
new file mode 100644
index 000000000..b633f487c
--- /dev/null
+++ b/host/lib/convert/convert_fc32_to_sc8_with_sse2.cpp
@@ -0,0 +1,150 @@
+//
+// Copyright 2012 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 "convert_common.hpp"
+#include <uhd/utils/byteswap.hpp>
+#include <emmintrin.h>
+
+using namespace uhd::convert;
+
+UHD_INLINE __m128i pack_sc32_4x_be(
+ const __m128 &in0, const __m128 &in1,
+ const __m128 &in2, const __m128 &in3,
+ const __m128 &scalar
+){
+ __m128i tmpi0 = _mm_cvtps_epi32(_mm_mul_ps(in0, scalar));
+ tmpi0 = _mm_shuffle_epi32(tmpi0, _MM_SHUFFLE(1, 0, 3, 2));
+ __m128i tmpi1 = _mm_cvtps_epi32(_mm_mul_ps(in1, scalar));
+ tmpi1 = _mm_shuffle_epi32(tmpi1, _MM_SHUFFLE(1, 0, 3, 2));
+ const __m128i lo = _mm_packs_epi32(tmpi0, tmpi1);
+
+ __m128i tmpi2 = _mm_cvtps_epi32(_mm_mul_ps(in2, scalar));
+ tmpi2 = _mm_shuffle_epi32(tmpi2, _MM_SHUFFLE(1, 0, 3, 2));
+ __m128i tmpi3 = _mm_cvtps_epi32(_mm_mul_ps(in3, scalar));
+ tmpi3 = _mm_shuffle_epi32(tmpi3, _MM_SHUFFLE(1, 0, 3, 2));
+ const __m128i hi = _mm_packs_epi32(tmpi2, tmpi3);
+
+ return _mm_packs_epi16(lo, hi);
+}
+
+UHD_INLINE __m128i pack_sc32_4x_le(
+ const __m128 &in0, const __m128 &in1,
+ const __m128 &in2, const __m128 &in3,
+ const __m128 &scalar
+){
+ __m128i tmpi0 = _mm_cvtps_epi32(_mm_mul_ps(in0, scalar));
+ tmpi0 = _mm_shuffle_epi32(tmpi0, _MM_SHUFFLE(2, 3, 0, 1));
+ __m128i tmpi1 = _mm_cvtps_epi32(_mm_mul_ps(in1, scalar));
+ tmpi1 = _mm_shuffle_epi32(tmpi1, _MM_SHUFFLE(2, 3, 0, 1));
+ const __m128i lo = _mm_packs_epi32(tmpi0, tmpi1);
+
+ __m128i tmpi2 = _mm_cvtps_epi32(_mm_mul_ps(in2, scalar));
+ tmpi2 = _mm_shuffle_epi32(tmpi2, _MM_SHUFFLE(2, 3, 0, 1));
+ __m128i tmpi3 = _mm_cvtps_epi32(_mm_mul_ps(in3, scalar));
+ tmpi3 = _mm_shuffle_epi32(tmpi3, _MM_SHUFFLE(2, 3, 0, 1));
+ const __m128i hi = _mm_packs_epi32(tmpi2, tmpi3);
+
+ return _mm_packs_epi16(lo, hi);
+}
+
+DECLARE_CONVERTER(fc32, 1, sc8_item32_be, 1, PRIORITY_SIMD){
+ const fc32_t *input = reinterpret_cast<const fc32_t *>(inputs[0]);
+ item32_t *output = reinterpret_cast<item32_t *>(outputs[0]);
+
+ const __m128 scalar = _mm_set_ps1(float(scale_factor));
+
+ #define convert_fc32_1_to_sc8_item32_1_bswap_guts(_al_) \
+ for (size_t j = 0; i+7 < nsamps; i+=8, j+=4){ \
+ /* load from input */ \
+ __m128 tmp0 = _mm_load ## _al_ ## ps(reinterpret_cast<const float *>(input+i+0)); \
+ __m128 tmp1 = _mm_load ## _al_ ## ps(reinterpret_cast<const float *>(input+i+2)); \
+ __m128 tmp2 = _mm_load ## _al_ ## ps(reinterpret_cast<const float *>(input+i+4)); \
+ __m128 tmp3 = _mm_load ## _al_ ## ps(reinterpret_cast<const float *>(input+i+6)); \
+ \
+ /* convert */ \
+ const __m128i tmpi = pack_sc32_4x_be(tmp0, tmp1, tmp2, tmp3, scalar); \
+ \
+ /* store to output */ \
+ _mm_storeu_si128(reinterpret_cast<__m128i *>(output+j), tmpi); \
+ } \
+
+ size_t i = 0;
+
+ //dispatch according to alignment
+ if ((size_t(input) & 0xf) == 0){
+ convert_fc32_1_to_sc8_item32_1_bswap_guts(_)
+ }
+ else{
+ convert_fc32_1_to_sc8_item32_1_bswap_guts(u_)
+ }
+
+ //convert remainder
+ const size_t num_pairs = nsamps/2;
+ for (size_t j = i/2; j < num_pairs; j++, i+=2){
+ const item32_t item = fc32_to_item32_sc8(input[i], input[i+1], scale_factor);
+ output[j] = uhd::byteswap(item);
+ }
+
+ if (nsamps != num_pairs*2){
+ const item32_t item = fc32_to_item32_sc8(input[nsamps-1], 0, scale_factor);
+ output[num_pairs] = uhd::byteswap(item);
+ }
+}
+
+DECLARE_CONVERTER(fc32, 1, sc8_item32_le, 1, PRIORITY_SIMD){
+ const fc32_t *input = reinterpret_cast<const fc32_t *>(inputs[0]);
+ item32_t *output = reinterpret_cast<item32_t *>(outputs[0]);
+
+ const __m128 scalar = _mm_set_ps1(float(scale_factor));
+
+ #define convert_fc32_1_to_sc8_item32_1_nswap_guts(_al_) \
+ for (size_t j = 0; i+7 < nsamps; i+=8, j+=4){ \
+ /* load from input */ \
+ __m128 tmp0 = _mm_load ## _al_ ## ps(reinterpret_cast<const float *>(input+i+0)); \
+ __m128 tmp1 = _mm_load ## _al_ ## ps(reinterpret_cast<const float *>(input+i+2)); \
+ __m128 tmp2 = _mm_load ## _al_ ## ps(reinterpret_cast<const float *>(input+i+4)); \
+ __m128 tmp3 = _mm_load ## _al_ ## ps(reinterpret_cast<const float *>(input+i+6)); \
+ \
+ /* convert */ \
+ const __m128i tmpi = pack_sc32_4x_le(tmp0, tmp1, tmp2, tmp3, scalar); \
+ \
+ /* store to output */ \
+ _mm_storeu_si128(reinterpret_cast<__m128i *>(output+j), tmpi); \
+ } \
+
+ size_t i = 0;
+
+ //dispatch according to alignment
+ if ((size_t(input) & 0xf) == 0){
+ convert_fc32_1_to_sc8_item32_1_nswap_guts(_)
+ }
+ else{
+ convert_fc32_1_to_sc8_item32_1_nswap_guts(u_)
+ }
+
+ //convert remainder
+ const size_t num_pairs = nsamps/2;
+ for (size_t j = i/2; j < num_pairs; j++, i+=2){
+ const item32_t item = fc32_to_item32_sc8(input[i], input[i+1], scale_factor);
+ output[j] = (item);
+ }
+
+ if (nsamps != num_pairs*2){
+ const item32_t item = fc32_to_item32_sc8(input[nsamps-1], 0, scale_factor);
+ output[num_pairs] = (item);
+ }
+}
diff --git a/host/lib/convert/convert_fc32_with_sse2.cpp b/host/lib/convert/convert_fc32_with_sse2.cpp
index 24a939d6c..97a3e8cdc 100644
--- a/host/lib/convert/convert_fc32_with_sse2.cpp
+++ b/host/lib/convert/convert_fc32_with_sse2.cpp
@@ -28,7 +28,7 @@ DECLARE_CONVERTER(fc32, 1, sc16_item32_le, 1, PRIORITY_SIMD){
const __m128 scalar = _mm_set_ps1(float(scale_factor));
#define convert_fc32_1_to_item32_1_nswap_guts(_al_) \
- for (; i+4 < nsamps; i+=4){ \
+ for (; i+3 < nsamps; i+=4){ \
/* load from input */ \
__m128 tmplo = _mm_load ## _al_ ## ps(reinterpret_cast<const float *>(input+i+0)); \
__m128 tmphi = _mm_load ## _al_ ## ps(reinterpret_cast<const float *>(input+i+2)); \
@@ -71,7 +71,7 @@ DECLARE_CONVERTER(fc32, 1, sc16_item32_be, 1, PRIORITY_SIMD){
const __m128 scalar = _mm_set_ps1(float(scale_factor));
#define convert_fc32_1_to_item32_1_bswap_guts(_al_) \
- for (; i+4 < nsamps; i+=4){ \
+ for (; i+3 < nsamps; i+=4){ \
/* load from input */ \
__m128 tmplo = _mm_load ## _al_ ## ps(reinterpret_cast<const float *>(input+i+0)); \
__m128 tmphi = _mm_load ## _al_ ## ps(reinterpret_cast<const float *>(input+i+2)); \
@@ -114,7 +114,7 @@ DECLARE_CONVERTER(sc16_item32_le, 1, fc32, 1, PRIORITY_SIMD){
const __m128i zeroi = _mm_setzero_si128();
#define convert_item32_1_to_fc32_1_nswap_guts(_al_) \
- for (; i+4 < nsamps; i+=4){ \
+ for (; i+3 < nsamps; i+=4){ \
/* load from input */ \
__m128i tmpi = _mm_loadu_si128(reinterpret_cast<const __m128i *>(input+i)); \
\
@@ -159,7 +159,7 @@ DECLARE_CONVERTER(sc16_item32_be, 1, fc32, 1, PRIORITY_SIMD){
const __m128i zeroi = _mm_setzero_si128();
#define convert_item32_1_to_fc32_1_bswap_guts(_al_) \
- for (; i+4 < nsamps; i+=4){ \
+ for (; i+3 < nsamps; i+=4){ \
/* load from input */ \
__m128i tmpi = _mm_loadu_si128(reinterpret_cast<const __m128i *>(input+i)); \
\
diff --git a/host/lib/convert/convert_fc64_to_sc8_with_sse2.cpp b/host/lib/convert/convert_fc64_to_sc8_with_sse2.cpp
new file mode 100644
index 000000000..405850601
--- /dev/null
+++ b/host/lib/convert/convert_fc64_to_sc8_with_sse2.cpp
@@ -0,0 +1,156 @@
+//
+// Copyright 2012 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 "convert_common.hpp"
+#include <uhd/utils/byteswap.hpp>
+#include <emmintrin.h>
+
+using namespace uhd::convert;
+
+UHD_INLINE __m128i pack_sc8_item32_4x(
+ const __m128i &in0, const __m128i &in1,
+ const __m128i &in2, const __m128i &in3
+){
+ const __m128i lo = _mm_packs_epi32(in0, in1);
+ const __m128i hi = _mm_packs_epi32(in2, in3);
+ return _mm_packs_epi16(lo, hi);
+}
+
+UHD_INLINE __m128i pack_sc32_4x_be(
+ const __m128d &lo, const __m128d &hi,
+ const __m128d &scalar
+){
+ const __m128i tmpi_lo = _mm_cvttpd_epi32(_mm_mul_pd(hi, scalar));
+ const __m128i tmpi_hi = _mm_cvttpd_epi32(_mm_mul_pd(lo, scalar));
+ return _mm_unpacklo_epi64(tmpi_lo, tmpi_hi);
+}
+
+UHD_INLINE __m128i pack_sc32_4x_le(
+ const __m128d &lo, const __m128d &hi,
+ const __m128d &scalar
+){
+ const __m128i tmpi_lo = _mm_cvttpd_epi32(_mm_mul_pd(lo, scalar));
+ const __m128i tmpi_hi = _mm_cvttpd_epi32(_mm_mul_pd(hi, scalar));
+ const __m128i tmpi = _mm_unpacklo_epi64(tmpi_lo, tmpi_hi);
+ return _mm_shuffle_epi32(tmpi, _MM_SHUFFLE(2, 3, 0, 1));
+}
+
+DECLARE_CONVERTER(fc64, 1, sc8_item32_be, 1, PRIORITY_SIMD){
+ const fc64_t *input = reinterpret_cast<const fc64_t *>(inputs[0]);
+ item32_t *output = reinterpret_cast<item32_t *>(outputs[0]);
+
+ const __m128d scalar = _mm_set1_pd(scale_factor);
+
+ #define convert_fc64_1_to_sc8_item32_1_bswap_guts(_al_) \
+ for (size_t j = 0; i+7 < nsamps; i+=8, j+=4){ \
+ /* load from input */ \
+ __m128d tmp0 = _mm_load ## _al_ ## pd(reinterpret_cast<const double *>(input+i+0)); \
+ __m128d tmp1 = _mm_load ## _al_ ## pd(reinterpret_cast<const double *>(input+i+1)); \
+ __m128d tmp2 = _mm_load ## _al_ ## pd(reinterpret_cast<const double *>(input+i+2)); \
+ __m128d tmp3 = _mm_load ## _al_ ## pd(reinterpret_cast<const double *>(input+i+3)); \
+ __m128d tmp4 = _mm_load ## _al_ ## pd(reinterpret_cast<const double *>(input+i+4)); \
+ __m128d tmp5 = _mm_load ## _al_ ## pd(reinterpret_cast<const double *>(input+i+5)); \
+ __m128d tmp6 = _mm_load ## _al_ ## pd(reinterpret_cast<const double *>(input+i+6)); \
+ __m128d tmp7 = _mm_load ## _al_ ## pd(reinterpret_cast<const double *>(input+i+7)); \
+ \
+ /* interleave */ \
+ const __m128i tmpi = pack_sc8_item32_4x( \
+ pack_sc32_4x_be(tmp0, tmp1, scalar), \
+ pack_sc32_4x_be(tmp2, tmp3, scalar), \
+ pack_sc32_4x_be(tmp4, tmp5, scalar), \
+ pack_sc32_4x_be(tmp6, tmp7, scalar) \
+ ); \
+ \
+ /* store to output */ \
+ _mm_storeu_si128(reinterpret_cast<__m128i *>(output+j), tmpi); \
+ } \
+
+ size_t i = 0;
+
+ //dispatch according to alignment
+ if ((size_t(input) & 0xf) == 0){
+ convert_fc64_1_to_sc8_item32_1_bswap_guts(_)
+ }
+ else{
+ convert_fc64_1_to_sc8_item32_1_bswap_guts(u_)
+ }
+
+ //convert remainder
+ const size_t num_pairs = nsamps/2;
+ for (size_t j = i/2; j < num_pairs; j++, i+=2){
+ const item32_t item = fc64_to_item32_sc8(input[i], input[i+1], scale_factor);
+ output[j] = uhd::byteswap(item);
+ }
+
+ if (nsamps != num_pairs*2){
+ const item32_t item = fc64_to_item32_sc8(input[nsamps-1], 0, scale_factor);
+ output[num_pairs] = uhd::byteswap(item);
+ }
+}
+
+DECLARE_CONVERTER(fc64, 1, sc8_item32_le, 1, PRIORITY_SIMD){
+ const fc64_t *input = reinterpret_cast<const fc64_t *>(inputs[0]);
+ item32_t *output = reinterpret_cast<item32_t *>(outputs[0]);
+
+ const __m128d scalar = _mm_set1_pd(scale_factor);
+
+ #define convert_fc64_1_to_sc8_item32_1_nswap_guts(_al_) \
+ for (size_t j = 0; i+7 < nsamps; i+=8, j+=4){ \
+ /* load from input */ \
+ __m128d tmp0 = _mm_load ## _al_ ## pd(reinterpret_cast<const double *>(input+i+0)); \
+ __m128d tmp1 = _mm_load ## _al_ ## pd(reinterpret_cast<const double *>(input+i+1)); \
+ __m128d tmp2 = _mm_load ## _al_ ## pd(reinterpret_cast<const double *>(input+i+2)); \
+ __m128d tmp3 = _mm_load ## _al_ ## pd(reinterpret_cast<const double *>(input+i+3)); \
+ __m128d tmp4 = _mm_load ## _al_ ## pd(reinterpret_cast<const double *>(input+i+4)); \
+ __m128d tmp5 = _mm_load ## _al_ ## pd(reinterpret_cast<const double *>(input+i+5)); \
+ __m128d tmp6 = _mm_load ## _al_ ## pd(reinterpret_cast<const double *>(input+i+6)); \
+ __m128d tmp7 = _mm_load ## _al_ ## pd(reinterpret_cast<const double *>(input+i+7)); \
+ \
+ /* interleave */ \
+ const __m128i tmpi = pack_sc8_item32_4x( \
+ pack_sc32_4x_le(tmp0, tmp1, scalar), \
+ pack_sc32_4x_le(tmp2, tmp3, scalar), \
+ pack_sc32_4x_le(tmp4, tmp5, scalar), \
+ pack_sc32_4x_le(tmp6, tmp7, scalar) \
+ ); \
+ \
+ /* store to output */ \
+ _mm_storeu_si128(reinterpret_cast<__m128i *>(output+j), tmpi); \
+ } \
+
+ size_t i = 0;
+
+ //dispatch according to alignment
+ if ((size_t(input) & 0xf) == 0){
+ convert_fc64_1_to_sc8_item32_1_nswap_guts(_)
+ }
+ else{
+ convert_fc64_1_to_sc8_item32_1_nswap_guts(u_)
+ }
+
+ //convert remainder
+ const size_t num_pairs = nsamps/2;
+ for (size_t j = i/2; j < num_pairs; j++, i+=2){
+ const item32_t item = fc64_to_item32_sc8(input[i], input[i+1], scale_factor);
+ output[j] = (item);
+ }
+
+ if (nsamps != num_pairs*2){
+ const item32_t item = fc64_to_item32_sc8(input[nsamps-1], 0, scale_factor);
+ output[num_pairs] = (item);
+ }
+}
diff --git a/host/lib/convert/convert_fc64_with_sse2.cpp b/host/lib/convert/convert_fc64_with_sse2.cpp
index 837bb584e..6e097e380 100644
--- a/host/lib/convert/convert_fc64_with_sse2.cpp
+++ b/host/lib/convert/convert_fc64_with_sse2.cpp
@@ -28,7 +28,7 @@ DECLARE_CONVERTER(fc64, 1, sc16_item32_le, 1, PRIORITY_SIMD){
const __m128d scalar = _mm_set1_pd(scale_factor);
#define convert_fc64_1_to_item32_1_nswap_guts(_al_) \
- for (; i+4 < nsamps; i+=4){ \
+ for (; i+3 < nsamps; i+=4){ \
/* load from input */ \
__m128d tmp0 = _mm_load ## _al_ ## pd(reinterpret_cast<const double *>(input+i+0)); \
__m128d tmp1 = _mm_load ## _al_ ## pd(reinterpret_cast<const double *>(input+i+1)); \
@@ -75,7 +75,7 @@ DECLARE_CONVERTER(fc64, 1, sc16_item32_be, 1, PRIORITY_SIMD){
const __m128d scalar = _mm_set1_pd(scale_factor);
#define convert_fc64_1_to_item32_1_bswap_guts(_al_) \
- for (; i+4 < nsamps; i+=4){ \
+ for (; i+3 < nsamps; i+=4){ \
/* load from input */ \
__m128d tmp0 = _mm_load ## _al_ ## pd(reinterpret_cast<const double *>(input+i+0)); \
__m128d tmp1 = _mm_load ## _al_ ## pd(reinterpret_cast<const double *>(input+i+1)); \
@@ -122,7 +122,7 @@ DECLARE_CONVERTER(sc16_item32_le, 1, fc64, 1, PRIORITY_SIMD){
const __m128i zeroi = _mm_setzero_si128();
#define convert_item32_1_to_fc64_1_nswap_guts(_al_) \
- for (; i+4 < nsamps; i+=4){ \
+ for (; i+3 < nsamps; i+=4){ \
/* load from input */ \
__m128i tmpi = _mm_loadu_si128(reinterpret_cast<const __m128i *>(input+i)); \
\
@@ -171,7 +171,7 @@ DECLARE_CONVERTER(sc16_item32_be, 1, fc64, 1, PRIORITY_SIMD){
const __m128i zeroi = _mm_setzero_si128();
#define convert_item32_1_to_fc64_1_bswap_guts(_al_) \
- for (; i+4 < nsamps; i+=4){ \
+ for (; i+3 < nsamps; i+=4){ \
/* load from input */ \
__m128i tmpi = _mm_loadu_si128(reinterpret_cast<const __m128i *>(input+i)); \
\
diff --git a/host/lib/convert/convert_orc.orc b/host/lib/convert/convert_orc.orc
index 5450bf4db..f7075606e 100644
--- a/host/lib/convert/convert_orc.orc
+++ b/host/lib/convert/convert_orc.orc
@@ -61,3 +61,20 @@ x2 swapw dst, tmp
.temp 4 tmp
x2 swapw tmp, src
swapl dst, tmp
+
+.function _convert_swap_byte_pairs_orc
+.source 4 src
+.dest 4 dst
+swapl dst, src
+
+.function _convert_fc32_1_to_sc8_1_nswap_orc
+.source 8 src
+.dest 2 dst
+.temp 8 tmp
+.temp 4 tmp2
+.floatparam 4 scalar
+x2 mulf tmp, src, scalar
+x2 convfl tmp, tmp
+swaplq tmp, tmp
+x2 convlw tmp2, tmp
+x2 convwb dst, tmp2
diff --git a/host/lib/convert/convert_with_orc.cpp b/host/lib/convert/convert_with_orc.cpp
index 0c46bcf1e..e44c8ca73 100644
--- a/host/lib/convert/convert_with_orc.cpp
+++ b/host/lib/convert/convert_with_orc.cpp
@@ -27,6 +27,8 @@ extern void _convert_item32_1_to_fc32_1_nswap_orc(void *, const void *, float, i
extern void _convert_item32_1_to_fc32_1_bswap_orc(void *, const void *, float, int);
extern void _convert_sc16_1_to_item32_1_nswap_orc(void *, const void *, float, int);
extern void _convert_item32_1_to_sc16_1_nswap_orc(void *, const void *, float, int);
+extern void _convert_fc32_1_to_sc8_1_nswap_orc(void *, const void *, float, int);
+extern void _convert_swap_byte_pairs_orc(void *, const void *, int);
}
DECLARE_CONVERTER(fc32, 1, sc16_item32_le, 1, PRIORITY_LIBORC){
@@ -52,3 +54,12 @@ DECLARE_CONVERTER(sc16, 1, sc16_item32_le, 1, PRIORITY_LIBORC){
DECLARE_CONVERTER(sc16_item32_le, 1, sc16, 1, PRIORITY_LIBORC){
_convert_item32_1_to_sc16_1_nswap_orc(outputs[0], inputs[0], scale_factor, nsamps);
}
+
+DECLARE_CONVERTER(fc32, 1, sc8_item32_be, 1, PRIORITY_LIBORC){
+ _convert_fc32_1_to_sc8_1_nswap_orc(outputs[0], inputs[0], scale_factor, nsamps);
+ _convert_swap_byte_pairs_orc(outputs[0], outputs[0], (nsamps + 1)/2);
+}
+
+DECLARE_CONVERTER(fc32, 1, sc8_item32_le, 1, PRIORITY_LIBORC){
+ _convert_fc32_1_to_sc8_1_nswap_orc(outputs[0], inputs[0], scale_factor, nsamps);
+}
diff --git a/host/lib/convert/convert_with_tables.cpp b/host/lib/convert/convert_with_tables.cpp
index c45415d5d..4a3ce29b2 100644
--- a/host/lib/convert/convert_with_tables.cpp
+++ b/host/lib/convert/convert_with_tables.cpp
@@ -1,5 +1,5 @@
//
-// Copyright 2011 Ettus Research LLC
+// Copyright 2011-2012 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
@@ -17,6 +17,7 @@
#include "convert_common.hpp"
#include <uhd/utils/byteswap.hpp>
+#include <boost/math/special_functions/round.hpp>
#include <vector>
using namespace uhd::convert;
@@ -26,6 +27,55 @@ static const size_t sc16_table_len = size_t(1 << 16);
typedef boost::uint16_t (*tohost16_type)(boost::uint16_t);
/***********************************************************************
+ * Implementation for sc16 to sc8 lookup table
+ * - Lookup the real and imaginary parts individually
+ **********************************************************************/
+template <bool swap>
+class convert_sc16_1_to_sc8_item32_1 : public converter{
+public:
+ convert_sc16_1_to_sc8_item32_1(void): _table(sc16_table_len){}
+
+ void set_scalar(const double scalar){
+ for (size_t i = 0; i < sc16_table_len; i++){
+ const boost::int16_t val = boost::uint16_t(i);
+ _table[i] = boost::int8_t(boost::math::iround(val * scalar / 32767.));
+ }
+ }
+
+ void operator()(const input_type &inputs, const output_type &outputs, const size_t nsamps){
+ const sc16_t *input = reinterpret_cast<const sc16_t *>(inputs[0]);
+ item32_t *output = reinterpret_cast<item32_t *>(outputs[0]);
+
+ const size_t num_pairs = nsamps/2;
+ for (size_t i = 0, j = 0; i < num_pairs; i++, j+=2){
+ output[i] = this->lookup(input[j], input[j+1]);
+ }
+
+ if (nsamps != num_pairs*2){
+ output[num_pairs] = this->lookup(input[nsamps-1], 0);;
+ }
+ }
+
+ item32_t lookup(const sc16_t &in0, const sc16_t &in1){
+ if (swap){ //hope this compiles out, its a template constant
+ return
+ (item32_t(_table[size_t(in0.real())]) << 16) |
+ (item32_t(_table[size_t(in0.imag())]) << 24) |
+ (item32_t(_table[size_t(in1.real())]) << 0) |
+ (item32_t(_table[size_t(in1.imag())]) << 8) ;
+ }
+ return
+ (item32_t(_table[size_t(in0.real())]) << 8) |
+ (item32_t(_table[size_t(in0.imag())]) << 0) |
+ (item32_t(_table[size_t(in1.real())]) << 24) |
+ (item32_t(_table[size_t(in1.imag())]) << 16) ;
+ }
+
+private:
+ std::vector<boost::uint8_t> _table;
+};
+
+/***********************************************************************
* Implementation for sc16 lookup table
* - Lookup the real and imaginary parts individually
**********************************************************************/
@@ -67,11 +117,19 @@ class convert_sc8_item32_1_to_fcxx_1 : public converter{
public:
convert_sc8_item32_1_to_fcxx_1(void): _table(sc16_table_len){}
+ //special case for sc16 type, 32767 undoes float normalization
+ static type conv(const boost::int8_t &num, const double scalar){
+ if (sizeof(type) == sizeof(s16_t)){
+ return type(boost::math::iround(num*scalar*32767));
+ }
+ return type(num*scalar);
+ }
+
void set_scalar(const double scalar){
for (size_t i = 0; i < sc16_table_len; i++){
const boost::uint16_t val = tohost(boost::uint16_t(i & 0xffff));
- const type real = type(boost::int8_t(val >> 8)*scalar);
- const type imag = type(boost::int8_t(val >> 0)*scalar);
+ const type real = conv(boost::int8_t(val >> 8), scalar);
+ const type imag = conv(boost::int8_t(val >> 0), scalar);
_table[i] = std::complex<type>(real, imag);
}
}
@@ -112,9 +170,13 @@ private:
#ifdef BOOST_BIG_ENDIAN
# define SHIFT_PAIR0 16, 0
# define SHIFT_PAIR1 0, 16
+# define BE_SWAP false
+# define LE_SWAP true
#else
# define SHIFT_PAIR0 0, 16
# define SHIFT_PAIR1 16, 0
+# define BE_SWAP true
+# define LE_SWAP false
#endif
static converter::sptr make_convert_sc16_item32_be_1_to_fc32_1(void){
@@ -149,6 +211,22 @@ static converter::sptr make_convert_sc8_item32_le_1_to_fc64_1(void){
return converter::sptr(new convert_sc8_item32_1_to_fcxx_1<double, uhd::wtohx, SHIFT_PAIR0>());
}
+static converter::sptr make_convert_sc8_item32_be_1_to_sc16_1(void){
+ return converter::sptr(new convert_sc8_item32_1_to_fcxx_1<s16_t, uhd::ntohx, SHIFT_PAIR1>());
+}
+
+static converter::sptr make_convert_sc8_item32_le_1_to_sc16_1(void){
+ return converter::sptr(new convert_sc8_item32_1_to_fcxx_1<s16_t, uhd::wtohx, SHIFT_PAIR0>());
+}
+
+static converter::sptr make_convert_sc16_1_to_sc8_item32_be_1(void){
+ return converter::sptr(new convert_sc16_1_to_sc8_item32_1<BE_SWAP>());
+}
+
+static converter::sptr make_convert_sc16_1_to_sc8_item32_le_1(void){
+ return converter::sptr(new convert_sc16_1_to_sc8_item32_1<LE_SWAP>());
+}
+
UHD_STATIC_BLOCK(register_convert_sc16_item32_1_to_fcxx_1){
uhd::convert::id_type id;
id.num_inputs = 1;
@@ -185,4 +263,20 @@ UHD_STATIC_BLOCK(register_convert_sc16_item32_1_to_fcxx_1){
id.output_format = "fc64";
id.input_format = "sc8_item32_le";
uhd::convert::register_converter(id, &make_convert_sc8_item32_le_1_to_fc64_1, PRIORITY_TABLE);
+
+ id.output_format = "sc16";
+ id.input_format = "sc8_item32_be";
+ uhd::convert::register_converter(id, &make_convert_sc8_item32_be_1_to_sc16_1, PRIORITY_TABLE);
+
+ id.output_format = "sc16";
+ id.input_format = "sc8_item32_le";
+ uhd::convert::register_converter(id, &make_convert_sc8_item32_le_1_to_sc16_1, PRIORITY_TABLE);
+
+ id.output_format = "sc16";
+ id.input_format = "sc8_item32_be";
+ uhd::convert::register_converter(id, &make_convert_sc16_1_to_sc8_item32_be_1, PRIORITY_TABLE);
+
+ id.output_format = "sc16";
+ id.input_format = "sc8_item32_le";
+ uhd::convert::register_converter(id, &make_convert_sc16_1_to_sc8_item32_le_1, PRIORITY_TABLE);
}
diff --git a/host/lib/convert/gen_convert_general.py b/host/lib/convert/gen_convert_general.py
index 46a0c8185..364c4bd1a 100644
--- a/host/lib/convert/gen_convert_general.py
+++ b/host/lib/convert/gen_convert_general.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python
#
-# Copyright 2011 Ettus Research LLC
+# Copyright 2011-2012 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
@@ -92,6 +92,22 @@ DECLARE_CONVERTER(sc8_item32_$(end), 1, $(cpu_type), 1, PRIORITY_GENERAL){
item32_sc8_to_$(cpu_type)(item_n, output[num_samps-1], dummy, scale_factor);
}
}
+
+DECLARE_CONVERTER($(cpu_type), 1, sc8_item32_$(end), 1, PRIORITY_GENERAL){
+ const $(cpu_type)_t *input = reinterpret_cast<const $(cpu_type)_t *>(inputs[0]);
+ item32_t *output = reinterpret_cast<item32_t *>(outputs[0]);
+
+ const size_t num_pairs = nsamps/2;
+ for (size_t i = 0, j = 0; i < num_pairs; i++, j+=2){
+ const item32_t item = $(cpu_type)_to_item32_sc8(input[j], input[j+1], scale_factor);
+ output[i] = $(to_wire)(item);
+ }
+
+ if (nsamps != num_pairs*2){
+ const item32_t item = $(cpu_type)_to_item32_sc8(input[nsamps-1], 0, scale_factor);
+ output[num_pairs] = $(to_wire)(item);
+ }
+}
"""
TMPL_CONV_USRP1_COMPLEX = """
diff --git a/host/lib/transport/gen_vrt_if_packet.py b/host/lib/transport/gen_vrt_if_packet.py
index 245a7ddbd..e28ce3aae 100755..100644
--- a/host/lib/transport/gen_vrt_if_packet.py
+++ b/host/lib/transport/gen_vrt_if_packet.py
@@ -137,7 +137,7 @@ void vrt::if_hdr_pack_$(suffix)(
#if $pred & $tlr_p
{
const size_t empty_bytes = if_packet_info.num_payload_words32*sizeof(boost::uint32_t) - if_packet_info.num_payload_bytes;
- if_packet_info.tlr |= (0x3 << 22) | (occ_table[empty_bytes & 0x3] << 10);
+ if_packet_info.tlr = (0x3 << 22) | (occ_table[empty_bytes & 0x3] << 10);
}
packet_buff[$num_header_words+if_packet_info.num_payload_words32] = $(XE_MACRO)(if_packet_info.tlr);
#set $flags |= (0x1 << 26);
diff --git a/host/lib/transport/libusb1_zero_copy.cpp b/host/lib/transport/libusb1_zero_copy.cpp
index 28d6cdd5b..3e67264cd 100644
--- a/host/lib/transport/libusb1_zero_copy.cpp
+++ b/host/lib/transport/libusb1_zero_copy.cpp
@@ -80,13 +80,14 @@ UHD_INLINE bool wait_for_completion(libusb_context *ctx, const double timeout, b
**********************************************************************/
class libusb_zero_copy_mrb : public managed_recv_buffer{
public:
- libusb_zero_copy_mrb(libusb_transfer *lut):
+ libusb_zero_copy_mrb(libusb_transfer *lut, const size_t frame_size):
_ctx(libusb::session::get_global_session()->get_context()),
- _lut(lut), _expired(false) { /* NOP */ }
+ _lut(lut), _expired(false), _frame_size(frame_size) { /* NOP */ }
void release(void){
if (_expired) return;
completed = false;
+ _lut->length = _frame_size; //always reset length
UHD_ASSERT_THROW(libusb_submit_transfer(_lut) == 0);
_expired = true;
}
@@ -109,6 +110,7 @@ private:
libusb_context *_ctx;
libusb_transfer *_lut;
bool _expired;
+ const size_t _frame_size;
};
/***********************************************************************
@@ -118,9 +120,9 @@ private:
**********************************************************************/
class libusb_zero_copy_msb : public managed_send_buffer{
public:
- libusb_zero_copy_msb(libusb_transfer *lut):
+ libusb_zero_copy_msb(libusb_transfer *lut, const size_t frame_size):
_ctx(libusb::session::get_global_session()->get_context()),
- _lut(lut), _expired(false) { /* NOP */ }
+ _lut(lut), _expired(false), _frame_size(frame_size) { /* NOP */ }
void commit(size_t len){
if (_expired) return;
@@ -144,11 +146,12 @@ public:
private:
void *get_buff(void) const{return _lut->buffer;}
- size_t get_size(void) const{return _lut->length;}
+ size_t get_size(void) const{return _frame_size;}
libusb_context *_ctx;
libusb_transfer *_lut;
bool _expired;
+ const size_t _frame_size;
};
/***********************************************************************
@@ -184,7 +187,7 @@ public:
libusb_transfer *lut = libusb_alloc_transfer(0);
UHD_ASSERT_THROW(lut != NULL);
- _mrb_pool.push_back(boost::shared_ptr<libusb_zero_copy_mrb>(new libusb_zero_copy_mrb(lut)));
+ _mrb_pool.push_back(boost::shared_ptr<libusb_zero_copy_mrb>(new libusb_zero_copy_mrb(lut, this->get_recv_frame_size())));
libusb_fill_bulk_transfer(
lut, // transfer
@@ -207,7 +210,7 @@ public:
libusb_transfer *lut = libusb_alloc_transfer(0);
UHD_ASSERT_THROW(lut != NULL);
- _msb_pool.push_back(boost::shared_ptr<libusb_zero_copy_msb>(new libusb_zero_copy_msb(lut)));
+ _msb_pool.push_back(boost::shared_ptr<libusb_zero_copy_msb>(new libusb_zero_copy_msb(lut, this->get_send_frame_size())));
libusb_fill_bulk_transfer(
lut, // transfer
diff --git a/host/lib/transport/super_recv_packet_handler.hpp b/host/lib/transport/super_recv_packet_handler.hpp
index a5876c8bf..74fbe82fb 100644
--- a/host/lib/transport/super_recv_packet_handler.hpp
+++ b/host/lib/transport/super_recv_packet_handler.hpp
@@ -1,5 +1,5 @@
//
-// Copyright 2011 Ettus Research LLC
+// Copyright 2011-2012 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
@@ -283,7 +283,7 @@ private:
info.ifpi.num_packet_words32 = num_packet_words32 - _header_offset_words32;
info.vrt_hdr = buff->cast<const boost::uint32_t *>() + _header_offset_words32;
_vrt_unpacker(info.vrt_hdr, info.ifpi);
- 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.time = time_spec_t::from_ticks(info.ifpi.tsf, _tick_rate); //assumes has_tsf is true
info.copy_buff = reinterpret_cast<const char *>(info.vrt_hdr + info.ifpi.num_header_words32);
//--------------------------------------------------------------
@@ -408,7 +408,7 @@ private:
case PACKET_INLINE_MESSAGE:
std::swap(curr_info, next_info); //save progress from curr -> next
- curr_info.metadata.has_time_spec = next_info[index].ifpi.has_tsi and next_info[index].ifpi.has_tsf;
+ curr_info.metadata.has_time_spec = next_info[index].ifpi.has_tsf;
curr_info.metadata.time_spec = next_info[index].time;
curr_info.metadata.more_fragments = false;
curr_info.metadata.fragment_offset = 0;
@@ -436,7 +436,7 @@ private:
alignment_check(index, curr_info);
std::swap(curr_info, next_info); //save progress from curr -> next
curr_info.metadata.has_time_spec = prev_info.metadata.has_time_spec;
- curr_info.metadata.time_spec = prev_info.metadata.time_spec + time_spec_t(0,
+ curr_info.metadata.time_spec = prev_info.metadata.time_spec + time_spec_t::from_ticks(
prev_info[index].ifpi.num_payload_words32*sizeof(boost::uint32_t)/_bytes_per_otw_item, _samp_rate);
curr_info.metadata.more_fragments = false;
curr_info.metadata.fragment_offset = 0;
@@ -469,7 +469,7 @@ private:
}
//set the metadata from the buffer information at index zero
- curr_info.metadata.has_time_spec = curr_info[0].ifpi.has_tsi and curr_info[0].ifpi.has_tsf;
+ curr_info.metadata.has_time_spec = curr_info[0].ifpi.has_tsf;
curr_info.metadata.time_spec = curr_info[0].time;
curr_info.metadata.more_fragments = false;
curr_info.metadata.fragment_offset = 0;
@@ -508,7 +508,7 @@ private:
metadata = info.metadata;
//interpolate the time spec (useful when this is a fragment)
- metadata.time_spec += time_spec_t(0, info.fragment_offset_in_samps, _samp_rate);
+ metadata.time_spec += time_spec_t::from_ticks(info.fragment_offset_in_samps, _samp_rate);
//extract the number of samples available to copy
const size_t nsamps_available = info.data_bytes_to_copy/_bytes_per_otw_item;
diff --git a/host/lib/transport/super_send_packet_handler.hpp b/host/lib/transport/super_send_packet_handler.hpp
index 5ed8e0143..3d68507ed 100644
--- a/host/lib/transport/super_send_packet_handler.hpp
+++ b/host/lib/transport/super_send_packet_handler.hpp
@@ -1,5 +1,5 @@
//
-// Copyright 2011 Ettus Research LLC
+// Copyright 2011-2012 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
@@ -134,11 +134,10 @@ public:
vrt::if_packet_info_t if_packet_info;
if_packet_info.has_sid = false;
if_packet_info.has_cid = false;
- if_packet_info.has_tlr = false;
- if_packet_info.has_tsi = metadata.has_time_spec;
+ if_packet_info.has_tlr = true;
+ if_packet_info.has_tsi = false;
if_packet_info.has_tsf = metadata.has_time_spec;
- if_packet_info.tsi = boost::uint32_t(metadata.time_spec.get_full_secs());
- if_packet_info.tsf = boost::uint64_t(metadata.time_spec.get_tick_count(_tick_rate));
+ if_packet_info.tsf = metadata.time_spec.to_ticks(_tick_rate);
if_packet_info.sob = metadata.start_of_burst;
if_packet_info.eob = metadata.end_of_burst;
@@ -174,9 +173,8 @@ public:
if (num_samps_sent == 0) return total_num_samps_sent;
//setup metadata for the next fragment
- const time_spec_t time_spec = metadata.time_spec + time_spec_t(0, total_num_samps_sent, _samp_rate);
- if_packet_info.tsi = boost::uint32_t(time_spec.get_full_secs());
- if_packet_info.tsf = boost::uint64_t(time_spec.get_tick_count(_tick_rate));
+ const time_spec_t time_spec = metadata.time_spec + time_spec_t::from_ticks(total_num_samps_sent, _samp_rate);
+ if_packet_info.tsf = time_spec.to_ticks(_tick_rate);
if_packet_info.sob = false;
}
diff --git a/host/lib/transport/usb_zero_copy_wrapper.cpp b/host/lib/transport/usb_zero_copy_wrapper.cpp
index 227c4b392..690e5aaa2 100644
--- a/host/lib/transport/usb_zero_copy_wrapper.cpp
+++ b/host/lib/transport/usb_zero_copy_wrapper.cpp
@@ -1,5 +1,5 @@
//
-// Copyright 2011 Ettus Research LLC
+// Copyright 2011-2012 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,17 +18,13 @@
#include <uhd/transport/usb_zero_copy.hpp>
#include <uhd/transport/bounded_buffer.hpp>
#include <uhd/transport/buffer_pool.hpp>
+#include <uhd/utils/byteswap.hpp>
+#include <uhd/utils/msg.hpp>
#include <boost/foreach.hpp>
#include <vector>
#include <iostream>
using namespace uhd::transport;
-bool debug = true;
-
-static inline size_t next_boundary(size_t length, size_t boundary){
- //pad to the boundary, assumes boundary is a power of 2
- return (length + (boundary-1)) & ~(boundary-1);
-}
/***********************************************************************
* USB zero copy wrapper - managed receive buffer
@@ -45,7 +41,7 @@ public:
_mrb.reset();
}
- sptr get_new(managed_recv_buffer::sptr mrb, const void *mem, size_t len){
+ UHD_INLINE sptr get_new(managed_recv_buffer::sptr mrb, const void *mem, size_t len){
_mrb = mrb;
_mem = mem;
_len = len;
@@ -67,28 +63,46 @@ private:
**********************************************************************/
class usb_zero_copy_wrapper_msb : public managed_send_buffer{
public:
- usb_zero_copy_wrapper_msb(bounded_buffer<usb_zero_copy_wrapper_msb *> &queue, size_t boundary):
- _queue(queue), _boundary(boundary){/*NOP*/}
+ usb_zero_copy_wrapper_msb(const usb_zero_copy::sptr internal, const size_t fragmentation_size):
+ _internal(internal), _fragmentation_size(fragmentation_size){/*NOP*/}
void commit(size_t len){
- if (_msb.get() == NULL) return;
- _msb->commit(next_boundary(len, _boundary));
- _queue.push_with_haste(this);
- _msb.reset();
+ if (len == 0) return;
+
+ //get a reference to the VITA header before incrementing
+ const boost::uint32_t vita_header = reinterpret_cast<const boost::uint32_t *>(_mem_buffer_tip)[0];
+
+ _bytes_in_buffer += len;
+ _mem_buffer_tip += len;
+
+ //extract VITA end of packet flag, we must force flush under eof conditions
+ const bool eop = (uhd::wtohx(vita_header) & (0x1 << 24)) != 0;
+ const bool full = _bytes_in_buffer >= (_last_send_buff->size() - _fragmentation_size);
+ if (eop or full){
+ _last_send_buff->commit(_bytes_in_buffer);
+ _last_send_buff.reset();
+ }
}
- sptr get_new(managed_send_buffer::sptr msb){
- _msb = msb;
+ UHD_INLINE sptr get_new(const double timeout){
+ if (not _last_send_buff){
+ _last_send_buff = _internal->get_send_buff(timeout);
+ if (not _last_send_buff) return sptr();
+ _mem_buffer_tip = _last_send_buff->cast<char *>();
+ _bytes_in_buffer = 0;
+ }
return make_managed_buffer(this);
}
private:
- void *get_buff(void) const{return _msb->cast<void *>();}
- size_t get_size(void) const{return _msb->size();}
-
- bounded_buffer<usb_zero_copy_wrapper_msb *> &_queue;
- size_t _boundary;
- managed_send_buffer::sptr _msb;
+ void *get_buff(void) const{return reinterpret_cast<void *>(_mem_buffer_tip);}
+ size_t get_size(void) const{return _fragmentation_size;}
+
+ usb_zero_copy::sptr _internal;
+ const size_t _fragmentation_size;
+ managed_send_buffer::sptr _last_send_buff;
+ size_t _bytes_in_buffer;
+ char *_mem_buffer_tip;
};
/***********************************************************************
@@ -96,23 +110,16 @@ private:
**********************************************************************/
class usb_zero_copy_wrapper : public usb_zero_copy{
public:
- usb_zero_copy_wrapper(
- sptr usb_zc, size_t usb_frame_boundary
- ):
+ usb_zero_copy_wrapper(sptr usb_zc, const size_t frame_boundary):
_internal_zc(usb_zc),
- _usb_frame_boundary(usb_frame_boundary),
+ _frame_boundary(frame_boundary),
_available_recv_buffs(this->get_num_recv_frames()),
- _available_send_buffs(this->get_num_send_frames()),
_mrb_pool(this->get_num_recv_frames(), usb_zero_copy_wrapper_mrb(_available_recv_buffs)),
- _msb_pool(this->get_num_send_frames(), usb_zero_copy_wrapper_msb(_available_send_buffs, usb_frame_boundary))
+ _the_only_msb(usb_zero_copy_wrapper_msb(usb_zc, frame_boundary))
{
BOOST_FOREACH(usb_zero_copy_wrapper_mrb &mrb, _mrb_pool){
_available_recv_buffs.push_with_haste(&mrb);
}
-
- BOOST_FOREACH(usb_zero_copy_wrapper_msb &msb, _msb_pool){
- _available_send_buffs.push_with_haste(&msb);
- }
}
managed_recv_buffer::sptr get_recv_buff(double timeout){
@@ -128,18 +135,17 @@ public:
//extract this packet's memory address and length in bytes
const char *mem = _last_recv_buff->cast<const char *>() + _last_recv_offset;
const boost::uint32_t *mem32 = reinterpret_cast<const boost::uint32_t *>(mem);
- size_t len = (mem32[0] & 0xffff)*sizeof(boost::uint32_t); //length in bytes (from VRT header)
-
+ const size_t len = (uhd::wtohx(mem32[0]) & 0xffff)*sizeof(boost::uint32_t); //length in bytes (from VRT header)
+
managed_recv_buffer::sptr recv_buff; //the buffer to be returned to the user
-
recv_buff = wmrb->get_new(_last_recv_buff, mem, len);
- _last_recv_offset = next_boundary(_last_recv_offset + len, _usb_frame_boundary);
-
+ _last_recv_offset += len;
+
//check if this receive buffer has been exhausted
if (_last_recv_offset >= _last_recv_buff->size()) {
_last_recv_buff.reset();
}
-
+
return recv_buff;
}
@@ -152,20 +158,11 @@ public:
}
size_t get_recv_frame_size(void) const{
- return _internal_zc->get_recv_frame_size();
+ return std::min(_frame_boundary, _internal_zc->get_recv_frame_size());
}
managed_send_buffer::sptr get_send_buff(double timeout){
- managed_send_buffer::sptr send_buff = _internal_zc->get_send_buff(timeout);
-
- //attempt to get a wrapper for a managed send buffer
- usb_zero_copy_wrapper_msb *wmsb = NULL;
- if (send_buff.get() and _available_send_buffs.pop_with_haste(wmsb)){
- return wmsb->get_new(send_buff);
- }
-
- //otherwise return a null sptr for failure
- return managed_send_buffer::sptr();
+ return _the_only_msb.get_new(timeout);
}
size_t get_num_send_frames(void) const{
@@ -173,20 +170,19 @@ public:
}
size_t get_send_frame_size(void) const{
- return _internal_zc->get_send_frame_size();
+ return std::min(_frame_boundary, _internal_zc->get_send_frame_size());
}
private:
sptr _internal_zc;
- size_t _usb_frame_boundary;
+ size_t _frame_boundary;
bounded_buffer<usb_zero_copy_wrapper_mrb *> _available_recv_buffs;
- bounded_buffer<usb_zero_copy_wrapper_msb *> _available_send_buffs;
std::vector<usb_zero_copy_wrapper_mrb> _mrb_pool;
- std::vector<usb_zero_copy_wrapper_msb> _msb_pool;
-
+ usb_zero_copy_wrapper_msb _the_only_msb;
+
//buffer to store partially-received VRT packets in
buffer_pool::sptr _fragment_mem;
-
+
//state for last recv buffer to create multiple managed buffers
managed_recv_buffer::sptr _last_recv_buff;
size_t _last_recv_offset;
diff --git a/host/lib/types/time_spec.cpp b/host/lib/types/time_spec.cpp
index 8e540c14c..14b9c988a 100644
--- a/host/lib/types/time_spec.cpp
+++ b/host/lib/types/time_spec.cpp
@@ -1,5 +1,5 @@
//
-// Copyright 2011 Ettus Research LLC
+// Copyright 2011-2012 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
@@ -16,6 +16,7 @@
//
#include <uhd/types/time_spec.hpp>
+#include <inttypes.h> //imaxdiv, intmax_t
using namespace uhd;
@@ -23,18 +24,6 @@ using namespace uhd;
* Time spec system time
**********************************************************************/
-/*!
- * Creates a time spec from system counts:
- * TODO make part of API as a static factory function
- * The counts type is 64 bits and will overflow the ticks type of long.
- * Therefore, divmod the counts into seconds + sub-second counts first.
- */
-#include <inttypes.h> //imaxdiv, intmax_t
-static UHD_INLINE time_spec_t time_spec_t_from_counts(intmax_t counts, intmax_t freq){
- imaxdiv_t divres = imaxdiv(counts, freq);
- return time_spec_t(time_t(divres.quot), double(divres.rem)/freq);
-}
-
#ifdef HAVE_CLOCK_GETTIME
#include <time.h>
time_spec_t time_spec_t::get_system_time(void){
@@ -49,7 +38,7 @@ time_spec_t time_spec_t::get_system_time(void){
time_spec_t time_spec_t::get_system_time(void){
mach_timebase_info_data_t info; mach_timebase_info(&info);
intmax_t nanosecs = mach_absolute_time()*info.numer/info.denom;
- return time_spec_t_from_counts(nanosecs, intmax_t(1e9));
+ return time_spec_t::from_ticks(nanosecs, 1e9);
}
#endif /* HAVE_MACH_ABSOLUTE_TIME */
@@ -60,7 +49,7 @@ time_spec_t time_spec_t::get_system_time(void){
LARGE_INTEGER counts, freq;
QueryPerformanceCounter(&counts);
QueryPerformanceFrequency(&freq);
- return time_spec_t_from_counts(counts.QuadPart, freq.QuadPart);
+ return time_spec_t::from_ticks(counts.QuadPart, freq.QuadPart);
}
#endif /* HAVE_QUERY_PERFORMANCE_COUNTER */
@@ -83,14 +72,21 @@ time_spec_t time_spec_t::get_system_time(void){
* Time spec constructors
**********************************************************************/
#define time_spec_init(full, frac) { \
- _full_secs = full + time_t(frac); \
- _frac_secs = frac - time_t(frac); \
+ const time_t _full = time_t(full); \
+ const double _frac = double(frac); \
+ const int _frac_int = int(_frac); \
+ _full_secs = _full + _frac_int; \
+ _frac_secs = _frac - _frac_int; \
if (_frac_secs < 0) {\
_full_secs -= 1; \
_frac_secs += 1; \
} \
}
+UHD_INLINE long long fast_llround(const double x){
+ return (long long)(x + 0.5); // assumption of non-negativity
+}
+
time_spec_t::time_spec_t(double secs){
time_spec_init(0, secs);
}
@@ -104,23 +100,25 @@ time_spec_t::time_spec_t(time_t full_secs, long tick_count, double tick_rate){
time_spec_init(full_secs, frac_secs);
}
+time_spec_t time_spec_t::from_ticks(long long ticks, double tick_rate){
+ const imaxdiv_t divres = imaxdiv(ticks, fast_llround(tick_rate));
+ return time_spec_t(time_t(divres.quot), double(divres.rem)/tick_rate);
+}
+
/***********************************************************************
* Time spec accessors
**********************************************************************/
long time_spec_t::get_tick_count(double tick_rate) const{
- return long(this->get_frac_secs()*tick_rate + 0.5);
-}
-
-double time_spec_t::get_real_secs(void) const{
- return this->_full_secs + this->_frac_secs;
+ return long(fast_llround(this->get_frac_secs()*tick_rate));
}
-time_t time_spec_t::get_full_secs(void) const{
- return this->_full_secs;
+long long time_spec_t::to_ticks(double tick_rate) const{
+ return fast_llround(this->get_frac_secs()*tick_rate) + \
+ (this->get_full_secs() * fast_llround(tick_rate));
}
-double time_spec_t::get_frac_secs(void) const{
- return this->_frac_secs;
+double time_spec_t::get_real_secs(void) const{
+ return this->get_full_secs() + this->get_frac_secs();
}
/***********************************************************************
@@ -128,16 +126,16 @@ double time_spec_t::get_frac_secs(void) const{
**********************************************************************/
time_spec_t &time_spec_t::operator+=(const time_spec_t &rhs){
time_spec_init(
- this->_full_secs + rhs.get_full_secs(),
- this->_frac_secs + rhs.get_frac_secs()
+ this->get_full_secs() + rhs.get_full_secs(),
+ this->get_frac_secs() + rhs.get_frac_secs()
);
return *this;
}
time_spec_t &time_spec_t::operator-=(const time_spec_t &rhs){
time_spec_init(
- this->_full_secs - rhs.get_full_secs(),
- this->_frac_secs - rhs.get_frac_secs()
+ this->get_full_secs() - rhs.get_full_secs(),
+ this->get_frac_secs() - rhs.get_frac_secs()
);
return *this;
}
diff --git a/host/lib/usrp/b100/b100_ctrl.cpp b/host/lib/usrp/b100/b100_ctrl.cpp
index 7d40daa32..e6136c00e 100644
--- a/host/lib/usrp/b100/b100_ctrl.cpp
+++ b/host/lib/usrp/b100/b100_ctrl.cpp
@@ -165,7 +165,7 @@ int b100_ctrl_impl::write(boost::uint32_t addr, const ctrl_data_t &data) {
pkt.pkt_meta.seq = _seq++;
pkt.pkt_meta.len = pkt.data.size();
pkt.pkt_meta.addr = addr;
- boost::uint16_t pkt_buff[CTRL_PACKET_LENGTH / sizeof(boost::uint16_t)];
+ 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);
@@ -181,7 +181,7 @@ ctrl_data_t b100_ctrl_impl::read(boost::uint32_t addr, size_t len) {
pkt.pkt_meta.seq = _seq++;
pkt.pkt_meta.len = len;
pkt.pkt_meta.addr = addr;
- boost::uint16_t pkt_buff[CTRL_PACKET_LENGTH / sizeof(boost::uint16_t)];
+ 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)){
diff --git a/host/lib/usrp/b100/b100_impl.cpp b/host/lib/usrp/b100/b100_impl.cpp
index 61bc58bce..8b55494c5 100644
--- a/host/lib/usrp/b100/b100_impl.cpp
+++ b/host/lib/usrp/b100/b100_impl.cpp
@@ -1,5 +1,5 @@
//
-// Copyright 2011 Ettus Research LLC
+// Copyright 2012 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
@@ -150,6 +150,10 @@ UHD_STATIC_BLOCK(register_b100_device){
* Structors
**********************************************************************/
b100_impl::b100_impl(const device_addr_t &device_addr){
+ size_t initialization_count = 0;
+ b100_impl_constructor_begin:
+ initialization_count++;
+
_tree = property_tree::make();
//extract the FPGA path for the B100
@@ -181,6 +185,8 @@ b100_impl::b100_impl(const device_addr_t &device_addr){
//load FPGA image, gpif is disabled while loading
this->enable_gpif(false);
_fx2_ctrl->usrp_load_fpga(b100_fpga_image);
+ _fx2_ctrl->usrp_fpga_reset(false); //active low reset
+ _fx2_ctrl->usrp_fpga_reset(true);
this->enable_gpif(true);
//create the control transport
@@ -196,13 +202,28 @@ b100_impl::b100_impl(const device_addr_t &device_addr){
3, 4, //interface, endpoint
ctrl_xport_args
);
+ while (_ctrl_transport->get_recv_buff(0.0)){} //flush ctrl xport
////////////////////////////////////////////////////////////////////
// Initialize FPGA wishbone communication
////////////////////////////////////////////////////////////////////
_fpga_ctrl = b100_ctrl::make(_ctrl_transport);
- this->reset_gpif(6); //always reset first to ensure communication
_fpga_ctrl->poke32(B100_REG_GLOBAL_RESET, 0); //global fpga reset
+ //perform a test peek operation
+ try{
+ _fpga_ctrl->peek32(0);
+ }
+ //try reset once in the case of failure
+ catch(const uhd::exception &e){
+ if (initialization_count > 1) throw;
+ UHD_MSG(warning) <<
+ "The control endpoint was left in a bad state.\n"
+ "Attempting endpoint re-enumeration...\n" << std::endl;
+ _fpga_ctrl.reset();
+ _ctrl_transport.reset();
+ _fx2_ctrl->usrp_fx2_reset();
+ goto b100_impl_constructor_begin;
+ }
this->check_fpga_compat(); //check after reset and making control
////////////////////////////////////////////////////////////////////
@@ -229,8 +250,10 @@ b100_impl::b100_impl(const device_addr_t &device_addr){
2, 6, // IN interface, endpoint
1, 2, // OUT interface, endpoint
data_xport_args // param hints
- )
+ ),
+ B100_MAX_PKT_BYTE_LIMIT
);
+ while (_data_transport->get_recv_buff(0.0)){} //flush data xport
////////////////////////////////////////////////////////////////////
// Initialize the properties tree
@@ -361,10 +384,10 @@ b100_impl::b100_impl(const device_addr_t &device_addr){
// 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_rb_bases.rb_hi_now = B100_REG_RB_TIME_NOW_HI;
+ time64_rb_bases.rb_lo_now = B100_REG_RB_TIME_NOW_LO;
+ time64_rb_bases.rb_hi_pps = B100_REG_RB_TIME_PPS_HI;
+ time64_rb_bases.rb_lo_pps = B100_REG_RB_TIME_PPS_LO;
_time64 = time64_core_200::make(
_fpga_ctrl, B100_REG_SR_ADDR(B100_SR_TIME64), time64_rb_bases
);
@@ -388,6 +411,13 @@ b100_impl::b100_impl(const device_addr_t &device_addr){
_tree->create<std::vector<std::string> >(mb_path / "clock_source/options").set(clock_sources);
////////////////////////////////////////////////////////////////////
+ // create user-defined control objects
+ ////////////////////////////////////////////////////////////////////
+ _user = user_settings_core_200::make(_fpga_ctrl, B100_REG_SR_ADDR(B100_SR_USER_REGS));
+ _tree->create<user_settings_core_200::user_reg_t>(mb_path / "user/regs")
+ .subscribe(boost::bind(&user_settings_core_200::set_reg, _user, _1));
+
+ ////////////////////////////////////////////////////////////////////
// create dboard control objects
////////////////////////////////////////////////////////////////////
@@ -505,10 +535,6 @@ void b100_impl::update_clock_source(const std::string &source){
}
////////////////// 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);
-}
-
void b100_impl::enable_gpif(const bool en) {
_fx2_ctrl->usrp_control_write(VRQ_ENABLE_GPIF, en ? 1 : 0, 0, 0, 0);
}
diff --git a/host/lib/usrp/b100/b100_impl.hpp b/host/lib/usrp/b100/b100_impl.hpp
index 96d90b14c..eab9c750b 100644
--- a/host/lib/usrp/b100/b100_impl.hpp
+++ b/host/lib/usrp/b100/b100_impl.hpp
@@ -1,5 +1,5 @@
//
-// Copyright 2011 Ettus Research LLC
+// Copyright 2011-2012 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
@@ -29,6 +29,7 @@
#include "rx_dsp_core_200.hpp"
#include "tx_dsp_core_200.hpp"
#include "time64_core_200.hpp"
+#include "user_settings_core_200.hpp"
#include <uhd/device.hpp>
#include <uhd/property_tree.hpp>
#include <uhd/utils/pimpl.hpp>
@@ -43,14 +44,15 @@
#include <uhd/transport/usb_zero_copy.hpp>
#include <boost/weak_ptr.hpp>
-static const double B100_LINK_RATE_BPS = 256e6/8; //pratical link rate (< 480 Mbps)
+static const double B100_LINK_RATE_BPS = 256e6/5; //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 = 0x08;
+static const boost::uint16_t B100_FW_COMPAT_NUM = 0x03;
+static const boost::uint16_t B100_FPGA_COMPAT_NUM = 0x09;
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;
+static const size_t B100_MAX_PKT_BYTE_LIMIT = 2048;
//! Make a b100 dboard interface
uhd::usrp::dboard_iface::sptr make_b100_dboard_iface(
@@ -84,6 +86,7 @@ private:
std::vector<rx_dsp_core_200::sptr> _rx_dsps;
tx_dsp_core_200::sptr _tx_dsp;
time64_core_200::sptr _time64;
+ user_settings_core_200::sptr _user;
b100_clock_ctrl::sptr _clock_ctrl;
b100_codec_ctrl::sptr _codec_ctrl;
b100_ctrl::sptr _fpga_ctrl;
@@ -120,7 +123,6 @@ private:
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);
diff --git a/host/lib/usrp/b100/b100_regs.hpp b/host/lib/usrp/b100/b100_regs.hpp
index 491e16eef..987a09f03 100644
--- a/host/lib/usrp/b100/b100_regs.hpp
+++ b/host/lib/usrp/b100/b100_regs.hpp
@@ -1,4 +1,19 @@
-
+//
+// Copyright 2010-2012 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/>.
+//
////////////////////////////////////////////////////////////////
//
@@ -27,10 +42,6 @@
#define B100_REG_MISC_SW B100_REG_MISC_BASE + 2
#define B100_REG_MISC_CGEN_CTRL B100_REG_MISC_BASE + 4
#define B100_REG_MISC_CGEN_ST B100_REG_MISC_BASE + 6
-#define B100_REG_MISC_TEST B100_REG_MISC_BASE + 8
-#define B100_REG_MISC_RX_LEN B100_REG_MISC_BASE + 10
-#define B100_REG_MISC_TX_LEN B100_REG_MISC_BASE + 12
-#define B100_REG_MISC_XFER_RATE B100_REG_MISC_BASE + 14
/////////////////////////////////////////////////////
// Slave 1 -- UART
@@ -65,10 +76,10 @@
#define B100_REG_RB_MUX_32_BASE B100_REG_SLAVE(7)
-#define B100_REG_RB_TIME_NOW_SECS B100_REG_RB_MUX_32_BASE + 0
-#define B100_REG_RB_TIME_NOW_TICKS B100_REG_RB_MUX_32_BASE + 4
-#define B100_REG_RB_TIME_PPS_SECS B100_REG_RB_MUX_32_BASE + 8
-#define B100_REG_RB_TIME_PPS_TICKS B100_REG_RB_MUX_32_BASE + 12
+#define B100_REG_RB_TIME_NOW_HI B100_REG_RB_MUX_32_BASE + 0
+#define B100_REG_RB_TIME_NOW_LO B100_REG_RB_MUX_32_BASE + 4
+#define B100_REG_RB_TIME_PPS_HI B100_REG_RB_MUX_32_BASE + 8
+#define B100_REG_RB_TIME_PPS_LO B100_REG_RB_MUX_32_BASE + 12
#define B100_REG_RB_MISC_TEST32 B100_REG_RB_MUX_32_BASE + 16
#define B100_REG_RB_COMPAT B100_REG_RB_MUX_32_BASE + 24
#define B100_REG_RB_GPIO B100_REG_RB_MUX_32_BASE + 28
@@ -92,9 +103,9 @@
#define B100_SR_TX_FRONT 54 // 5 regs (+0 to +4)
#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_CLEAR_FIFO 61 // 1 reg
#define B100_SR_GLOBAL_RESET 63 // 1 reg
+#define B100_SR_USER_REGS 64 // 2 regs
#define B100_SR_GPIO 128
@@ -105,8 +116,7 @@
/////////////////////////////////////////////////
// Magic reset regs
////////////////////////////////////////////////
-#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_CLEAR_FIFO B100_REG_SR_ADDR(B100_SR_CLEAR_FIFO)
#define B100_REG_GLOBAL_RESET B100_REG_SR_ADDR(B100_SR_GLOBAL_RESET)
#endif
diff --git a/host/lib/usrp/b100/io_impl.cpp b/host/lib/usrp/b100/io_impl.cpp
index 494d5d123..674380cca 100644
--- a/host/lib/usrp/b100/io_impl.cpp
+++ b/host/lib/usrp/b100/io_impl.cpp
@@ -1,5 +1,5 @@
//
-// Copyright 2011 Ettus Research LLC
+// Copyright 2011-2012 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
@@ -17,6 +17,7 @@
#include "recv_packet_demuxer.hpp"
#include "validate_subdev_spec.hpp"
+#include "async_packet_handler.hpp"
#include "../../transport/super_recv_packet_handler.hpp"
#include "../../transport/super_send_packet_handler.hpp"
#include "usrp_commands.h"
@@ -41,12 +42,13 @@ using namespace uhd::transport;
**********************************************************************/
struct b100_impl::io_impl{
io_impl(void):
- async_msg_fifo(100/*messages deep*/)
+ async_msg_fifo(1000/*messages deep*/)
{ /* NOP */ }
zero_copy_if::sptr data_transport;
bounded_buffer<async_metadata_t> async_msg_fifo;
recv_packet_demuxer::sptr demuxer;
+ double tick_rate;
};
/***********************************************************************
@@ -54,12 +56,8 @@ struct b100_impl::io_impl{
**********************************************************************/
void b100_impl::io_init(void){
- //clear state machines
- _fpga_ctrl->poke32(B100_REG_CLEAR_RX, 0);
- _fpga_ctrl->poke32(B100_REG_CLEAR_TX, 0);
-
- //set the expected packet size in USB frames
- _fpga_ctrl->poke32(B100_REG_MISC_RX_LEN, 4);
+ //clear fifo state machines
+ _fpga_ctrl->poke32(B100_REG_CLEAR_FIFO, 0);
//allocate streamer weak ptrs containers
_rx_streamers.resize(_rx_dsps.size());
@@ -85,26 +83,16 @@ void b100_impl::handle_async_message(managed_recv_buffer::sptr rbuf){
}
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));
+ load_metadata_from_buff(uhd::wtohx<boost::uint32_t>, metadata, if_packet_info, vrt_hdr, _io_impl->tick_rate);
+
+ //push the message onto the queue
_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 if (metadata.event_code &
- async_metadata_t::EVENT_CODE_TIME_ERROR
- ) UHD_MSG(fastpath) << "L";
+
+ //print some fastpath messages
+ standard_async_msg_prints(metadata);
}
else UHD_MSG(error) << "Unknown async packet" << std::endl;
}
@@ -123,6 +111,8 @@ void b100_impl::update_rates(void){
}
void b100_impl::update_tick_rate(const double rate){
+ _io_impl->tick_rate = rate;
+
//update the tick rate on all existing streamers -> thread safe
for (size_t i = 0; i < _rx_streamers.size(); i++){
boost::shared_ptr<sph::recv_packet_streamer> my_streamer =
@@ -154,6 +144,8 @@ void b100_impl::update_tx_samp_rate(const size_t dspno, const double rate){
if (my_streamer.get() == NULL) return;
my_streamer->set_samp_rate(rate);
+ const double adj = _tx_dsp->get_scaling_adjustment();
+ my_streamer->set_scale_factor(adj);
}
void b100_impl::update_rx_subdev_spec(const uhd::usrp::subdev_spec_t &spec){
@@ -202,15 +194,15 @@ rx_streamer::sptr b100_impl::get_rx_stream(const uhd::stream_args_t &args_){
//setup defaults for unspecified values
args.otw_format = args.otw_format.empty()? "sc16" : args.otw_format;
args.channels = args.channels.empty()? std::vector<size_t>(1, 0) : args.channels;
- const unsigned sc8_scalar = unsigned(args.args.cast<double>("scalar", 0x400));
//calculate packet size
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
+ - sizeof(vrt::if_packet_info_t().tsi) //no int time ever used
;
- const size_t bpp = 2048 - hdr_size; //limited by FPGA pkt buffer size
+ const size_t bpp = _data_transport->get_recv_frame_size() - hdr_size;
const size_t bpi = convert::get_bytes_per_item(args.otw_format);
const size_t spp = unsigned(args.args.cast<double>("spp", bpp/bpi));
@@ -233,8 +225,7 @@ rx_streamer::sptr b100_impl::get_rx_stream(const uhd::stream_args_t &args_){
for (size_t chan_i = 0; chan_i < args.channels.size(); chan_i++){
const size_t dsp = args.channels[chan_i];
_rx_dsps[dsp]->set_nsamps_per_packet(spp); //seems to be a good place to set this
- if (not args.args.has_key("noclear")) _rx_dsps[dsp]->clear();
- _rx_dsps[dsp]->set_format(args.otw_format, sc8_scalar);
+ _rx_dsps[dsp]->setup(args);
my_streamer->set_xport_chan_get_buff(chan_i, boost::bind(
&recv_packet_demuxer::get_recv_buff, _io_impl->demuxer, dsp, _1
), true /*flush*/);
@@ -260,16 +251,15 @@ tx_streamer::sptr b100_impl::get_tx_stream(const uhd::stream_args_t &args_){
args.otw_format = args.otw_format.empty()? "sc16" : args.otw_format;
args.channels = args.channels.empty()? std::vector<size_t>(1, 0) : args.channels;
- if (args.otw_format != "sc16"){
- throw uhd::value_error("USRP TX cannot handle requested wire format: " + args.otw_format);
- }
-
//calculate packet size
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().sid) //no stream id ever used
- sizeof(vrt::if_packet_info_t().cid) //no class id ever used
+ - sizeof(vrt::if_packet_info_t().tsi) //no int time ever used
;
- static const size_t bpp = 2048 - hdr_size;
+ static const size_t bpp = _data_transport->get_send_frame_size() - hdr_size;
const size_t spp = bpp/convert::get_bytes_per_item(args.otw_format);
//make the new streamer given the samples per packet
@@ -291,8 +281,7 @@ tx_streamer::sptr b100_impl::get_tx_stream(const uhd::stream_args_t &args_){
for (size_t chan_i = 0; chan_i < args.channels.size(); chan_i++){
const size_t dsp = args.channels[chan_i];
UHD_ASSERT_THROW(dsp == 0); //always 0
- if (not args.args.has_key("noclear")) _tx_dsp->clear();
- if (args.args.has_key("underflow_policy")) _tx_dsp->set_underflow_policy(args.args["underflow_policy"]);
+ _tx_dsp->setup(args);
my_streamer->set_xport_chan_get_buff(chan_i, boost::bind(
&zero_copy_if::get_send_buff, _data_transport, _1
));
diff --git a/host/lib/usrp/common/async_packet_handler.hpp b/host/lib/usrp/common/async_packet_handler.hpp
new file mode 100644
index 000000000..fef03483f
--- /dev/null
+++ b/host/lib/usrp/common/async_packet_handler.hpp
@@ -0,0 +1,71 @@
+//
+// Copyright 2012 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_ASYNC_PACKET_HANDLER_HPP
+#define INCLUDED_LIBUHD_USRP_COMMON_ASYNC_PACKET_HANDLER_HPP
+
+#include <uhd/config.hpp>
+#include <uhd/transport/vrt_if_packet.hpp>
+#include <uhd/types/metadata.hpp>
+#include <uhd/utils/byteswap.hpp>
+#include <uhd/utils/msg.hpp>
+
+namespace uhd{ namespace usrp{
+
+ template <typename to_host_type>
+ void load_metadata_from_buff(
+ const to_host_type &to_host,
+ async_metadata_t &metadata,
+ const transport::vrt::if_packet_info_t &if_packet_info,
+ const boost::uint32_t *vrt_hdr,
+ const double tick_rate,
+ const size_t channel = 0
+ ){
+ const boost::uint32_t *payload = vrt_hdr + if_packet_info.num_header_words32;
+
+ //load into metadata
+ metadata.channel = channel;
+ metadata.has_time_spec = if_packet_info.has_tsf;
+ metadata.time_spec = time_spec_t::from_ticks(if_packet_info.tsf, tick_rate);
+ metadata.event_code = async_metadata_t::event_code_t(to_host(payload[0]) & 0xff);
+
+ //load user payload
+ for (size_t i = 1; i < if_packet_info.num_payload_words32; i++){
+ if (i-1 == 4) break; //limit of 4 words32
+ metadata.user_payload[i-1] = to_host(payload[i]);
+ }
+ }
+
+ UHD_INLINE void standard_async_msg_prints(const async_metadata_t &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 if (metadata.event_code &
+ async_metadata_t::EVENT_CODE_TIME_ERROR
+ ) UHD_MSG(fastpath) << "L";
+ }
+
+
+}} //namespace uhd::usrp
+
+#endif /* INCLUDED_LIBUHD_USRP_COMMON_ASYNC_PACKET_HANDLER_HPP */
diff --git a/host/lib/usrp/common/fx2_ctrl.cpp b/host/lib/usrp/common/fx2_ctrl.cpp
index 3c6df7079..7b8920eb1 100644
--- a/host/lib/usrp/common/fx2_ctrl.cpp
+++ b/host/lib/usrp/common/fx2_ctrl.cpp
@@ -139,6 +139,15 @@ public:
_ctrl_transport = ctrl_transport;
}
+ void usrp_fx2_reset(void){
+ unsigned char reset_y = 1;
+ unsigned char reset_n = 0;
+ usrp_control_write(FX2_FIRMWARE_LOAD, 0xe600, 0, &reset_y, 1);
+ usrp_control_write(FX2_FIRMWARE_LOAD, 0xe600, 0, &reset_n, 1);
+ //wait for things to settle
+ boost::this_thread::sleep(boost::posix_time::milliseconds(2000));
+ }
+
void usrp_load_firmware(std::string filestring, bool force)
{
const char *filename = filestring.c_str();
@@ -419,7 +428,7 @@ public:
{
UHD_ASSERT_THROW(bytes.size() < max_i2c_data_bytes);
- unsigned char buff[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,
@@ -434,7 +443,7 @@ public:
{
UHD_ASSERT_THROW(num_bytes < max_i2c_data_bytes);
- unsigned char buff[max_i2c_data_bytes];
+ unsigned char buff[max_i2c_data_bytes] = {};
int ret = this->usrp_i2c_read(addr & 0xff,
buff,
num_bytes);
diff --git a/host/lib/usrp/common/fx2_ctrl.hpp b/host/lib/usrp/common/fx2_ctrl.hpp
index 691d64275..f2e060862 100644
--- a/host/lib/usrp/common/fx2_ctrl.hpp
+++ b/host/lib/usrp/common/fx2_ctrl.hpp
@@ -39,6 +39,9 @@ public:
//! Call init after the fpga is loaded
virtual void usrp_init(void) = 0;
+ //! For emergency situations
+ virtual void usrp_fx2_reset(void) = 0;
+
/*!
* Load firmware in Intel HEX Format onto device
* \param filename name of firmware file
@@ -116,6 +119,9 @@ public:
//! enable/disable the tx path
virtual void usrp_tx_enable(bool on) = 0;
+
+ //! reset the fpga
+ virtual void usrp_fpga_reset(bool on) = 0;
};
}} //namespace uhd::usrp
diff --git a/host/lib/usrp/cores/CMakeLists.txt b/host/lib/usrp/cores/CMakeLists.txt
index 2aa8f6b99..aa5f0bcbb 100644
--- a/host/lib/usrp/cores/CMakeLists.txt
+++ b/host/lib/usrp/cores/CMakeLists.txt
@@ -1,5 +1,5 @@
#
-# Copyright 2011 Ettus Research LLC
+# Copyright 2011-2012 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
@@ -30,4 +30,5 @@ LIBUHD_APPEND_SOURCES(
${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
+ ${CMAKE_CURRENT_SOURCE_DIR}/user_settings_core_200.cpp
)
diff --git a/host/lib/usrp/cores/rx_dsp_core_200.cpp b/host/lib/usrp/cores/rx_dsp_core_200.cpp
index 2e21cc895..0996952ff 100644
--- a/host/lib/usrp/cores/rx_dsp_core_200.cpp
+++ b/host/lib/usrp/cores/rx_dsp_core_200.cpp
@@ -1,5 +1,5 @@
//
-// Copyright 2011 Ettus Research LLC
+// Copyright 2011-2012 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,6 +18,7 @@
#include "rx_dsp_core_200.hpp"
#include <uhd/types/dict.hpp>
#include <uhd/exception.hpp>
+#include <uhd/utils/msg.hpp>
#include <uhd/utils/algorithm.hpp>
#include <boost/assign/list_of.hpp>
#include <boost/thread/thread.hpp> //thread sleep
@@ -27,7 +28,7 @@
#include <cmath>
#define REG_DSP_RX_FREQ _dsp_base + 0
-//skip one right here
+#define REG_DSP_RX_SCALE_IQ _dsp_base + 4
#define REG_DSP_RX_DECIM _dsp_base + 8
#define REG_DSP_RX_MUX _dsp_base + 12
@@ -35,15 +36,15 @@
#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_TIME_HI _ctrl_base + 4
+#define REG_RX_CTRL_TIME_LO _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
-#define REG_RX_CTRL_FORMAT _ctrl_base + 36
+#define REG_RX_CTRL_FORMAT REG_RX_CTRL_CLEAR //re-use clear address
template <class T> T ceil_log2(T num){
return std::ceil(std::log(num)/std::log(T(2)));
@@ -60,6 +61,10 @@ public:
):
_iface(iface), _dsp_base(dsp_base), _ctrl_base(ctrl_base), _sid(sid)
{
+ //init to something so update method has reasonable defaults
+ _scaling_adjustment = 1.0;
+ _dsp_extra_scaling = 1.0;
+
//This is a hack/fix for the lingering packet problem.
//The caller should also flush the recv transports
if (lingering_packet){
@@ -78,7 +83,6 @@ public:
_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);
@@ -117,8 +121,9 @@ public:
//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
+ const boost::uint64_t ticks = (stream_cmd.stream_now)? 0 : stream_cmd.time_spec.to_ticks(_tick_rate);
+ _iface->poke32(REG_RX_CTRL_TIME_HI, boost::uint32_t(ticks >> 32));
+ _iface->poke32(REG_RX_CTRL_TIME_LO, boost::uint32_t(ticks >> 0)); //latches the command
}
void set_mux(const std::string &mode, const bool fe_swapped){
@@ -175,12 +180,20 @@ public:
// 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);
+ this->update_scalar();
return _tick_rate/decim_rate;
}
+ void update_scalar(void){
+ const double target_scalar = (1 << 16)*_scaling_adjustment/_dsp_extra_scaling;
+ const boost::int32_t actual_scalar = boost::math::iround(target_scalar);
+ _fxpt_scalar_correction = target_scalar/actual_scalar; //should be small
+ _iface->poke32(REG_DSP_RX_SCALE_IQ, actual_scalar);
+ }
+
double get_scaling_adjustment(void){
- return _scaling_adjustment/_fxpt_scale_adj;
+ return _fxpt_scalar_correction*_host_extra_scaling/32767.;
}
double set_freq(const double freq_){
@@ -210,22 +223,27 @@ public:
if (_continuous_streaming) issue_stream_command(stream_cmd_t::STREAM_MODE_START_CONTINUOUS);
}
- void set_format(const std::string &format, const unsigned scale){
+ void setup(const uhd::stream_args_t &stream_args){
+ if (not stream_args.args.has_key("noclear")) this->clear();
+
unsigned format_word = 0;
- if (format == "sc16"){
+ if (stream_args.otw_format == "sc16"){
format_word = 0;
- _fxpt_scale_adj = 32767.;
+ _dsp_extra_scaling = 1.0;
+ _host_extra_scaling = 1.0;
}
- else if (format == "sc8"){
- format_word = (1 << 18);
- _fxpt_scale_adj = 127. * scale;
- _fxpt_scale_adj /= 256; //engine 16to8 drops lower 8 bits
- _fxpt_scale_adj /= 4; //scale operation 2-bit pad
+ else if (stream_args.otw_format == "sc8"){
+ format_word = (1 << 0);
+ double peak = stream_args.args.cast<double>("peak", 1.0);
+ peak = std::max(peak, 1.0/256);
+ _host_extra_scaling = peak*256;
+ _dsp_extra_scaling = peak*256;
}
- else throw uhd::value_error("USRP RX cannot handle requested wire format: " + format);
+ else throw uhd::value_error("USRP RX cannot handle requested wire format: " + stream_args.otw_format);
+
+ this->update_scalar();
- const unsigned scale_word = scale & 0x3ffff; //18 bits;
- _iface->poke32(REG_RX_CTRL_FORMAT, format_word | scale_word);
+ _iface->poke32(REG_RX_CTRL_FORMAT, format_word);
}
private:
@@ -233,7 +251,7 @@ private:
const size_t _dsp_base, _ctrl_base;
double _tick_rate, _link_rate;
bool _continuous_streaming;
- double _scaling_adjustment, _fxpt_scale_adj;
+ double _scaling_adjustment, _dsp_extra_scaling, _host_extra_scaling, _fxpt_scalar_correction;
const boost::uint32_t _sid;
};
diff --git a/host/lib/usrp/cores/rx_dsp_core_200.hpp b/host/lib/usrp/cores/rx_dsp_core_200.hpp
index 58be51eee..b01f751e9 100644
--- a/host/lib/usrp/cores/rx_dsp_core_200.hpp
+++ b/host/lib/usrp/cores/rx_dsp_core_200.hpp
@@ -19,6 +19,7 @@
#define INCLUDED_LIBUHD_USRP_RX_DSP_CORE_200_HPP
#include <uhd/config.hpp>
+#include <uhd/stream.hpp>
#include <uhd/types/ranges.hpp>
#include <boost/utility.hpp>
#include <boost/shared_ptr.hpp>
@@ -60,7 +61,7 @@ public:
virtual void handle_overflow(void) = 0;
- virtual void set_format(const std::string &format, const unsigned scale) = 0;
+ virtual void setup(const uhd::stream_args_t &stream_args) = 0;
};
#endif /* INCLUDED_LIBUHD_USRP_RX_DSP_CORE_200_HPP */
diff --git a/host/lib/usrp/cores/time64_core_200.cpp b/host/lib/usrp/cores/time64_core_200.cpp
index 23d1bdea2..e460d1106 100644
--- a/host/lib/usrp/cores/time64_core_200.cpp
+++ b/host/lib/usrp/cores/time64_core_200.cpp
@@ -20,11 +20,10 @@
#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_TICKS_HI _base + 0
+#define REG_TIME64_TICKS_LO _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)
@@ -59,39 +58,42 @@ public:
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);
+ const boost::uint32_t ticks_hi = _iface->peek32(_readback_bases.rb_hi_now);
+ const boost::uint32_t ticks_lo = _iface->peek32(_readback_bases.rb_lo_now);
+ if (ticks_hi != _iface->peek32(_readback_bases.rb_hi_now)) continue;
+ const boost::uint64_t ticks = (boost::uint64_t(ticks_hi) << 32) | ticks_lo;
+ return time_spec_t::from_ticks(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);
+ const boost::uint32_t ticks_hi = _iface->peek32(_readback_bases.rb_hi_pps);
+ const boost::uint32_t ticks_lo = _iface->peek32(_readback_bases.rb_lo_pps);
+ if (ticks_hi != _iface->peek32(_readback_bases.rb_hi_pps)) continue;
+ const boost::uint64_t ticks = (boost::uint64_t(ticks_hi) << 32) | ticks_lo;
+ return time_spec_t::from_ticks(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));
+ const boost::uint64_t ticks = time.to_ticks(_tick_rate);
+ _iface->poke32(REG_TIME64_TICKS_LO, boost::uint32_t(ticks >> 0));
_iface->poke32(REG_TIME64_IMM, FLAG_TIME64_LATCH_NOW);
- _iface->poke32(REG_TIME64_SECS, boost::uint32_t(time.get_full_secs())); //latches all 3
+ _iface->poke32(REG_TIME64_TICKS_HI, boost::uint32_t(ticks >> 32)); //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));
+ const boost::uint64_t ticks = time.to_ticks(_tick_rate);
+ _iface->poke32(REG_TIME64_TICKS_LO, boost::uint32_t(ticks >> 0));
_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
+ _iface->poke32(REG_TIME64_TICKS_HI, boost::uint32_t(ticks >> 32)); //latches all 3
}
void set_time_source(const std::string &source){
diff --git a/host/lib/usrp/cores/time64_core_200.hpp b/host/lib/usrp/cores/time64_core_200.hpp
index ebd51a02f..7571573a5 100644
--- a/host/lib/usrp/cores/time64_core_200.hpp
+++ b/host/lib/usrp/cores/time64_core_200.hpp
@@ -31,8 +31,8 @@ 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;
+ size_t rb_hi_now, rb_lo_now;
+ size_t rb_hi_pps, rb_lo_pps;
};
//! makes a new time64 core from iface and slave base
diff --git a/host/lib/usrp/cores/tx_dsp_core_200.cpp b/host/lib/usrp/cores/tx_dsp_core_200.cpp
index c5de4e361..7f02d59ca 100644
--- a/host/lib/usrp/cores/tx_dsp_core_200.cpp
+++ b/host/lib/usrp/cores/tx_dsp_core_200.cpp
@@ -1,5 +1,5 @@
//
-// Copyright 2011 Ettus Research LLC
+// Copyright 2011-2012 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,10 +18,12 @@
#include "tx_dsp_core_200.hpp"
#include <uhd/types/dict.hpp>
#include <uhd/exception.hpp>
+#include <uhd/utils/msg.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 <boost/thread/thread.hpp> //sleep
#include <algorithm>
#include <cmath>
@@ -29,8 +31,8 @@
#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_CLEAR _ctrl_base + 0
+#define REG_TX_CTRL_FORMAT _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
@@ -58,14 +60,19 @@ public:
):
_iface(iface), _dsp_base(dsp_base), _ctrl_base(ctrl_base), _sid(sid)
{
+ //init to something so update method has reasonable defaults
+ _scaling_adjustment = 1.0;
+ _dsp_extra_scaling = 1.0;
+
//init the tx control registers
this->clear();
this->set_underflow_policy("next_packet");
}
void clear(void){
- _iface->poke32(REG_TX_CTRL_CLEAR_STATE, 1); //reset
- _iface->poke32(REG_TX_CTRL_NUM_CHAN, 0); //1 channel
+ _iface->poke32(REG_TX_CTRL_CLEAR, 1); //reset and flush technique
+ boost::this_thread::sleep(boost::posix_time::milliseconds(10));
+ _iface->poke32(REG_TX_CTRL_CLEAR, 0);
_iface->poke32(REG_TX_CTRL_REPORT_SID, _sid);
}
@@ -121,13 +128,24 @@ public:
// 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));
+ const double rate_pow = std::pow(double(interp & 0xff), 3);
+ _scaling_adjustment = std::pow(2, ceil_log2(rate_pow))/(1.65*rate_pow);
+ this->update_scalar();
return _tick_rate/interp_rate;
}
+ void update_scalar(void){
+ const double target_scalar = (1 << 17)*_scaling_adjustment/_dsp_extra_scaling;
+ const boost::int32_t actual_scalar = boost::math::iround(target_scalar);
+ _fxpt_scalar_correction = target_scalar/actual_scalar; //should be small
+ _iface->poke32(REG_DSP_TX_SCALE_IQ, actual_scalar);
+ }
+
+ double get_scaling_adjustment(void){
+ return _fxpt_scalar_correction*_host_extra_scaling*32767.;
+ }
+
double set_freq(const double freq_){
//correct for outside of rate (wrap around)
double freq = std::fmod(freq_, _tick_rate);
@@ -156,10 +174,38 @@ public:
_iface->poke32(REG_TX_CTRL_PACKETS_PER_UP, (packets_per_up == 0)? 0 : (FLAG_TX_CTRL_UP_ENB | packets_per_up));
}
+ void setup(const uhd::stream_args_t &stream_args){
+ if (not stream_args.args.has_key("noclear")) this->clear();
+
+ unsigned format_word = 0;
+ if (stream_args.otw_format == "sc16"){
+ format_word = 0;
+ _dsp_extra_scaling = 1.0;
+ _host_extra_scaling = 1.0;
+ }
+ else if (stream_args.otw_format == "sc8"){
+ format_word = (1 << 0);
+ double peak = stream_args.args.cast<double>("peak", 1.0);
+ peak = std::max(peak, 1.0/256);
+ _host_extra_scaling = 1.0/peak/256;
+ _dsp_extra_scaling = 1.0/peak;
+ }
+ else throw uhd::value_error("USRP TX cannot handle requested wire format: " + stream_args.otw_format);
+
+ this->update_scalar();
+
+ _iface->poke32(REG_TX_CTRL_FORMAT, format_word);
+
+ if (stream_args.args.has_key("underflow_policy")){
+ this->set_underflow_policy(stream_args.args["underflow_policy"]);
+ }
+ }
+
private:
wb_iface::sptr _iface;
const size_t _dsp_base, _ctrl_base;
double _tick_rate, _link_rate;
+ double _scaling_adjustment, _dsp_extra_scaling, _host_extra_scaling, _fxpt_scalar_correction;
const boost::uint32_t _sid;
};
diff --git a/host/lib/usrp/cores/tx_dsp_core_200.hpp b/host/lib/usrp/cores/tx_dsp_core_200.hpp
index 4b39a5b07..0e1cfb6bc 100644
--- a/host/lib/usrp/cores/tx_dsp_core_200.hpp
+++ b/host/lib/usrp/cores/tx_dsp_core_200.hpp
@@ -19,6 +19,7 @@
#define INCLUDED_LIBUHD_USRP_TX_DSP_CORE_200_HPP
#include <uhd/config.hpp>
+#include <uhd/stream.hpp>
#include <uhd/types/ranges.hpp>
#include <boost/utility.hpp>
#include <boost/shared_ptr.hpp>
@@ -44,14 +45,15 @@ public:
virtual uhd::meta_range_t get_host_rates(void) = 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 set_updates(const size_t cycles_per_up, const size_t packets_per_up) = 0;
- virtual void set_underflow_policy(const std::string &policy) = 0;
-
+ virtual void setup(const uhd::stream_args_t &stream_args) = 0;
};
#endif /* INCLUDED_LIBUHD_USRP_TX_DSP_CORE_200_HPP */
diff --git a/host/lib/usrp/cores/user_settings_core_200.cpp b/host/lib/usrp/cores/user_settings_core_200.cpp
new file mode 100644
index 000000000..d262631b1
--- /dev/null
+++ b/host/lib/usrp/cores/user_settings_core_200.cpp
@@ -0,0 +1,43 @@
+//
+// Copyright 2012 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 "user_settings_core_200.hpp"
+
+#define REG_USER_ADDR _base + 0
+#define REG_USER_DATA _base + 4
+
+class user_settings_core_200_impl : public user_settings_core_200{
+public:
+ user_settings_core_200_impl(wb_iface::sptr iface, const size_t base):
+ _iface(iface), _base(base)
+ {
+ //NOP
+ }
+
+ void set_reg(const user_reg_t &reg){
+ _iface->poke32(REG_USER_ADDR, reg.first);
+ _iface->poke32(REG_USER_DATA, reg.second);
+ }
+
+private:
+ wb_iface::sptr _iface;
+ const size_t _base;
+};
+
+user_settings_core_200::sptr user_settings_core_200::make(wb_iface::sptr iface, const size_t base){
+ return sptr(new user_settings_core_200_impl(iface, base));
+}
diff --git a/host/lib/usrp/cores/user_settings_core_200.hpp b/host/lib/usrp/cores/user_settings_core_200.hpp
new file mode 100644
index 000000000..1f5d13de7
--- /dev/null
+++ b/host/lib/usrp/cores/user_settings_core_200.hpp
@@ -0,0 +1,36 @@
+//
+// Copyright 2012 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_USER_SETTINGS_CORE_200_HPP
+#define INCLUDED_LIBUHD_USRP_USER_SETTINGS_CORE_200_HPP
+
+#include <uhd/config.hpp>
+#include <boost/utility.hpp>
+#include <boost/shared_ptr.hpp>
+#include "wb_iface.hpp"
+
+class user_settings_core_200 : boost::noncopyable{
+public:
+ typedef boost::shared_ptr<user_settings_core_200> sptr;
+ typedef std::pair<boost::uint8_t, boost::uint32_t> user_reg_t;
+
+ static sptr make(wb_iface::sptr iface, const size_t base);
+
+ virtual void set_reg(const user_reg_t &reg) = 0;
+};
+
+#endif /* INCLUDED_LIBUHD_USRP_USER_SETTINGS_CORE_200_HPP */
diff --git a/host/lib/usrp/e100/e100_impl.cpp b/host/lib/usrp/e100/e100_impl.cpp
index f58138ae6..a01ce4a7b 100644
--- a/host/lib/usrp/e100/e100_impl.cpp
+++ b/host/lib/usrp/e100/e100_impl.cpp
@@ -1,5 +1,5 @@
//
-// Copyright 2010-2011 Ettus Research LLC
+// Copyright 2010-2012 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
@@ -326,10 +326,10 @@ e100_impl::e100_impl(const uhd::device_addr_t &device_addr){
// 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_rb_bases.rb_hi_now = E100_REG_RB_TIME_NOW_HI;
+ time64_rb_bases.rb_lo_now = E100_REG_RB_TIME_NOW_LO;
+ time64_rb_bases.rb_hi_pps = E100_REG_RB_TIME_PPS_HI;
+ time64_rb_bases.rb_lo_pps = E100_REG_RB_TIME_PPS_LO;
_time64 = time64_core_200::make(
_fpga_ctrl, E100_REG_SR_ADDR(UE_SR_TIME64), time64_rb_bases
);
@@ -353,6 +353,13 @@ e100_impl::e100_impl(const uhd::device_addr_t &device_addr){
_tree->create<std::vector<std::string> >(mb_path / "clock_source/options").set(clock_sources);
////////////////////////////////////////////////////////////////////
+ // create user-defined control objects
+ ////////////////////////////////////////////////////////////////////
+ _user = user_settings_core_200::make(_fpga_ctrl, E100_REG_SR_ADDR(UE_SR_USER_REGS));
+ _tree->create<user_settings_core_200::user_reg_t>(mb_path / "user/regs")
+ .subscribe(boost::bind(&user_settings_core_200::set_reg, _user, _1));
+
+ ////////////////////////////////////////////////////////////////////
// create dboard control objects
////////////////////////////////////////////////////////////////////
diff --git a/host/lib/usrp/e100/e100_impl.hpp b/host/lib/usrp/e100/e100_impl.hpp
index 2ea890375..1d36cb2ac 100644
--- a/host/lib/usrp/e100/e100_impl.hpp
+++ b/host/lib/usrp/e100/e100_impl.hpp
@@ -1,5 +1,5 @@
//
-// Copyright 2010-2011 Ettus Research LLC
+// Copyright 2010-2012 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
@@ -25,6 +25,7 @@
#include "rx_dsp_core_200.hpp"
#include "tx_dsp_core_200.hpp"
#include "time64_core_200.hpp"
+#include "user_settings_core_200.hpp"
#include <uhd/device.hpp>
#include <uhd/property_tree.hpp>
#include <uhd/utils/pimpl.hpp>
@@ -48,7 +49,7 @@ static const double E100_RX_LINK_RATE_BPS = 166e6/3/2*2;
static const double E100_TX_LINK_RATE_BPS = 166e6/3/1*2;
static const std::string E100_I2C_DEV_NODE = "/dev/i2c-3";
static const std::string E100_UART_DEV_NODE = "/dev/ttyO0";
-static const boost::uint16_t E100_FPGA_COMPAT_NUM = 0x08;
+static const boost::uint16_t E100_FPGA_COMPAT_NUM = 0x09;
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;
@@ -92,6 +93,7 @@ private:
std::vector<rx_dsp_core_200::sptr> _rx_dsps;
tx_dsp_core_200::sptr _tx_dsp;
time64_core_200::sptr _time64;
+ user_settings_core_200::sptr _user;
e100_clock_ctrl::sptr _clock_ctrl;
e100_codec_ctrl::sptr _codec_ctrl;
e100_ctrl::sptr _fpga_ctrl;
diff --git a/host/lib/usrp/e100/e100_regs.hpp b/host/lib/usrp/e100/e100_regs.hpp
index f24f5895b..75be2cfbe 100644
--- a/host/lib/usrp/e100/e100_regs.hpp
+++ b/host/lib/usrp/e100/e100_regs.hpp
@@ -1,4 +1,19 @@
-
+//
+// Copyright 2010-2012 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/>.
+//
////////////////////////////////////////////////////////////////
//
@@ -71,10 +86,10 @@
#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_TIME_NOW_HI E100_REG_RB_MUX_32_BASE + 0
+#define E100_REG_RB_TIME_NOW_LO E100_REG_RB_MUX_32_BASE + 4
+#define E100_REG_RB_TIME_PPS_HI E100_REG_RB_MUX_32_BASE + 8
+#define E100_REG_RB_TIME_PPS_LO 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
#define E100_REG_RB_COMPAT E100_REG_RB_MUX_32_BASE + 24
@@ -101,9 +116,9 @@
#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_CLEAR_FIFO 61 // 1 reg
#define UE_SR_GLOBAL_RESET 63 // 1 reg
+#define UE_SR_USER_REGS 64 // 2 regs
#define UE_SR_GPIO 128
@@ -115,8 +130,7 @@
/////////////////////////////////////////////////
// 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_CLEAR_FIFO E100_REG_SR_ADDR(UE_SR_CLEAR_FIFO)
#define E100_REG_GLOBAL_RESET E100_REG_SR_ADDR(UE_SR_GLOBAL_RESET)
#endif
diff --git a/host/lib/usrp/e100/io_impl.cpp b/host/lib/usrp/e100/io_impl.cpp
index 441e32a8d..e9608125f 100644
--- a/host/lib/usrp/e100/io_impl.cpp
+++ b/host/lib/usrp/e100/io_impl.cpp
@@ -1,5 +1,5 @@
//
-// Copyright 2010-2011 Ettus Research LLC
+// Copyright 2010-2012 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
@@ -17,6 +17,7 @@
#include "recv_packet_demuxer.hpp"
#include "validate_subdev_spec.hpp"
+#include "async_packet_handler.hpp"
#include "../../transport/super_recv_packet_handler.hpp"
#include "../../transport/super_send_packet_handler.hpp"
#include <linux/usrp_e.h> //ioctl structures and constants
@@ -50,7 +51,7 @@ using namespace uhd::transport;
**********************************************************************/
struct e100_impl::io_impl{
io_impl(void):
- false_alarm(0), async_msg_fifo(100/*messages deep*/)
+ false_alarm(0), async_msg_fifo(1000/*messages deep*/)
{ /* NOP */ }
double tick_rate; //set by update tick rate method
@@ -123,28 +124,13 @@ void e100_impl::io_impl::handle_irq(void){
//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));
+ load_metadata_from_buff(uhd::wtohx<boost::uint32_t>, metadata, if_packet_info, data.buf, tick_rate);
//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";
- else if (metadata.event_code &
- async_metadata_t::EVENT_CODE_TIME_ERROR
- ) UHD_MSG(fastpath) << "L";
+ standard_async_msg_prints(metadata);
}
//prepare for the next round
@@ -164,9 +150,8 @@ void e100_impl::io_init(void){
_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);
+ //clear fifo state machines
+ _fpga_ctrl->poke32(E100_REG_CLEAR_FIFO, 0);
//allocate streamer weak ptrs containers
_rx_streamers.resize(_rx_dsps.size());
@@ -217,6 +202,8 @@ void e100_impl::update_tx_samp_rate(const size_t dspno, const double rate){
if (my_streamer.get() == NULL) return;
my_streamer->set_samp_rate(rate);
+ const double adj = _tx_dsp->get_scaling_adjustment();
+ my_streamer->set_scale_factor(adj);
}
void e100_impl::update_rates(void){
@@ -278,13 +265,13 @@ rx_streamer::sptr e100_impl::get_rx_stream(const uhd::stream_args_t &args_){
//setup defaults for unspecified values
args.otw_format = args.otw_format.empty()? "sc16" : args.otw_format;
args.channels = args.channels.empty()? std::vector<size_t>(1, 0) : args.channels;
- const unsigned sc8_scalar = unsigned(args.args.cast<double>("scalar", 0x400));
//calculate packet size
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
+ - sizeof(vrt::if_packet_info_t().tsi) //no int time ever used
;
const size_t bpp = _data_transport->get_recv_frame_size() - hdr_size;
const size_t bpi = convert::get_bytes_per_item(args.otw_format);
@@ -309,8 +296,7 @@ rx_streamer::sptr e100_impl::get_rx_stream(const uhd::stream_args_t &args_){
for (size_t chan_i = 0; chan_i < args.channels.size(); chan_i++){
const size_t dsp = args.channels[chan_i];
_rx_dsps[dsp]->set_nsamps_per_packet(spp); //seems to be a good place to set this
- if (not args.args.has_key("noclear")) _rx_dsps[dsp]->clear();
- _rx_dsps[dsp]->set_format(args.otw_format, sc8_scalar);
+ _rx_dsps[dsp]->setup(args);
my_streamer->set_xport_chan_get_buff(chan_i, boost::bind(
&recv_packet_demuxer::get_recv_buff, _io_impl->demuxer, dsp, _1
), true /*flush*/);
@@ -336,14 +322,13 @@ tx_streamer::sptr e100_impl::get_tx_stream(const uhd::stream_args_t &args_){
args.otw_format = args.otw_format.empty()? "sc16" : args.otw_format;
args.channels = args.channels.empty()? std::vector<size_t>(1, 0) : args.channels;
- if (args.otw_format != "sc16"){
- throw uhd::value_error("USRP TX cannot handle requested wire format: " + args.otw_format);
- }
-
//calculate packet size
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().sid) //no stream id ever used
- sizeof(vrt::if_packet_info_t().cid) //no class id ever used
+ - sizeof(vrt::if_packet_info_t().tsi) //no int time ever used
;
static const size_t bpp = _data_transport->get_send_frame_size() - hdr_size;
const size_t spp = bpp/convert::get_bytes_per_item(args.otw_format);
@@ -367,8 +352,7 @@ tx_streamer::sptr e100_impl::get_tx_stream(const uhd::stream_args_t &args_){
for (size_t chan_i = 0; chan_i < args.channels.size(); chan_i++){
const size_t dsp = args.channels[chan_i];
UHD_ASSERT_THROW(dsp == 0); //always 0
- if (not args.args.has_key("noclear")) _tx_dsp->clear();
- if (args.args.has_key("underflow_policy")) _tx_dsp->set_underflow_policy(args.args["underflow_policy"]);
+ _tx_dsp->setup(args);
my_streamer->set_xport_chan_get_buff(chan_i, boost::bind(
&zero_copy_if::get_send_buff, _data_transport, _1
));
diff --git a/host/lib/usrp/multi_usrp.cpp b/host/lib/usrp/multi_usrp.cpp
index 6cd9f95bb..d9be19b83 100644
--- a/host/lib/usrp/multi_usrp.cpp
+++ b/host/lib/usrp/multi_usrp.cpp
@@ -445,6 +445,17 @@ public:
return _tree->list(mb_root(mboard) / "sensors");
}
+ void set_user_register(const boost::uint8_t addr, const boost::uint32_t data, size_t mboard){
+ if (mboard != ALL_MBOARDS){
+ typedef std::pair<boost::uint8_t, boost::uint32_t> user_reg_t;
+ _tree->access<user_reg_t>(mb_root(mboard) / "user/reg").set(user_reg_t(addr, data));
+ return;
+ }
+ for (size_t m = 0; m < get_num_mboards(); m++){
+ set_user_register(addr, data, m);
+ }
+ }
+
/*******************************************************************
* RX methods
******************************************************************/
diff --git a/host/lib/usrp/usrp1/io_impl.cpp b/host/lib/usrp/usrp1/io_impl.cpp
index e9d9b65c2..f27135562 100644
--- a/host/lib/usrp/usrp1/io_impl.cpp
+++ b/host/lib/usrp/usrp1/io_impl.cpp
@@ -1,5 +1,5 @@
//
-// Copyright 2010-2011 Ettus Research LLC
+// Copyright 2010-2012 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
@@ -221,17 +221,17 @@ void usrp1_impl::io_init(void){
_io_impl = UHD_PIMPL_MAKE(io_impl, (_data_transport));
- //create a new vandal thread to poll xerflow conditions
- _io_impl->vandal_task = task::make(boost::bind(
- &usrp1_impl::vandal_conquest_loop, this
- ));
-
//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();
+
+ //create a new vandal thread to poll xerflow conditions
+ _io_impl->vandal_task = task::make(boost::bind(
+ &usrp1_impl::vandal_conquest_loop, this
+ ));
}
void usrp1_impl::rx_stream_on_off(bool enb){
diff --git a/host/lib/usrp/usrp1/soft_time_ctrl.cpp b/host/lib/usrp/usrp1/soft_time_ctrl.cpp
index b8af8af06..90b3a92da 100644
--- a/host/lib/usrp/usrp1/soft_time_ctrl.cpp
+++ b/host/lib/usrp/usrp1/soft_time_ctrl.cpp
@@ -39,8 +39,8 @@ public:
_nsamps_remaining(0),
_stream_mode(stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS),
_cmd_queue(2),
- _async_msg_queue(100),
- _inline_msg_queue(100),
+ _async_msg_queue(1000),
+ _inline_msg_queue(1000),
_stream_on_off(stream_on_off)
{
//synchronously spawn a new thread
diff --git a/host/lib/usrp/usrp1/usrp1_impl.cpp b/host/lib/usrp/usrp1/usrp1_impl.cpp
index ef8ae950d..430ea59c8 100644
--- a/host/lib/usrp/usrp1/usrp1_impl.cpp
+++ b/host/lib/usrp/usrp1/usrp1_impl.cpp
@@ -210,6 +210,7 @@ usrp1_impl::usrp1_impl(const device_addr_t &device_addr){
////////////////////////////////////////////////////////////////////
// Initialize the properties tree
////////////////////////////////////////////////////////////////////
+ _rx_dc_offset_shadow = 0;
_tree = property_tree::make();
_tree->create<std::string>("/name").set("USRP1 Device");
const fs_path mb_path = "/mboards/0";
diff --git a/host/lib/usrp/usrp2/fw_common.h b/host/lib/usrp/usrp2/fw_common.h
index 1af1db860..0babf7445 100644
--- a/host/lib/usrp/usrp2/fw_common.h
+++ b/host/lib/usrp/usrp2/fw_common.h
@@ -30,9 +30,9 @@ extern "C" {
#endif
//fpga and firmware compatibility numbers
-#define USRP2_FPGA_COMPAT_NUM 8
+#define USRP2_FPGA_COMPAT_NUM 9
#define USRP2_FW_COMPAT_NUM 11
-#define USRP2_FW_VER_MINOR 1
+#define USRP2_FW_VER_MINOR 2
//used to differentiate control packets over data port
#define USRP2_INVALID_VRT_HEADER 0
diff --git a/host/lib/usrp/usrp2/io_impl.cpp b/host/lib/usrp/usrp2/io_impl.cpp
index e3fa46920..d32ffb62c 100644
--- a/host/lib/usrp/usrp2/io_impl.cpp
+++ b/host/lib/usrp/usrp2/io_impl.cpp
@@ -1,5 +1,5 @@
//
-// Copyright 2010-2011 Ettus Research LLC
+// Copyright 2010-2012 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
@@ -16,6 +16,7 @@
//
#include "validate_subdev_spec.hpp"
+#include "async_packet_handler.hpp"
#include "../../transport/super_recv_packet_handler.hpp"
#include "../../transport/super_send_packet_handler.hpp"
#include "usrp2_impl.hpp"
@@ -135,7 +136,8 @@ private:
struct usrp2_impl::io_impl{
io_impl(void):
- async_msg_fifo(100/*messages deep*/)
+ async_msg_fifo(1000/*messages deep*/),
+ tick_rate(1 /*non-zero default*/)
{
/* NOP */
}
@@ -201,12 +203,7 @@ void usrp2_impl::io_impl::recv_pirate_loop(
//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), tick_rate
- );
- metadata.event_code = async_metadata_t::event_code_t(sph::get_context_code(vrt_hdr, if_packet_info));
+ load_metadata_from_buff(uhd::ntohx<boost::uint32_t>, metadata, if_packet_info, vrt_hdr, tick_rate, index);
//catch the flow control packets and react
if (metadata.event_code == 0){
@@ -217,17 +214,7 @@ void usrp2_impl::io_impl::recv_pirate_loop(
//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 if (metadata.event_code &
- async_metadata_t::EVENT_CODE_TIME_ERROR
- ) UHD_MSG(fastpath) << "L";
+ standard_async_msg_prints(metadata);
}
else{
//TODO unknown received packet, may want to print error...
@@ -307,6 +294,8 @@ void usrp2_impl::update_tx_samp_rate(const std::string &mb, const size_t dsp, co
if (my_streamer.get() == NULL) return;
my_streamer->set_samp_rate(rate);
+ const double adj = _mbc[mb].tx_dsp->get_scaling_adjustment();
+ my_streamer->set_scale_factor(adj);
}
void usrp2_impl::update_rates(void){
@@ -380,13 +369,13 @@ rx_streamer::sptr usrp2_impl::get_rx_stream(const uhd::stream_args_t &args_){
//setup defaults for unspecified values
args.otw_format = args.otw_format.empty()? "sc16" : args.otw_format;
args.channels = args.channels.empty()? std::vector<size_t>(1, 0) : args.channels;
- const unsigned sc8_scalar = unsigned(args.args.cast<double>("scalar", 0x400));
//calculate packet size
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
+ - sizeof(vrt::if_packet_info_t().tsi) //no int time ever used
;
const size_t bpp = _mbc[_mbc.keys().front()].rx_dsp_xports[0]->get_recv_frame_size() - hdr_size;
const size_t bpi = convert::get_bytes_per_item(args.otw_format);
@@ -416,8 +405,7 @@ rx_streamer::sptr usrp2_impl::get_rx_stream(const uhd::stream_args_t &args_){
if (chan < num_chan_so_far){
const size_t dsp = chan + _mbc[mb].rx_chan_occ - num_chan_so_far;
_mbc[mb].rx_dsps[dsp]->set_nsamps_per_packet(spp); //seems to be a good place to set this
- if (not args.args.has_key("noclear")) _mbc[mb].rx_dsps[dsp]->clear();
- _mbc[mb].rx_dsps[dsp]->set_format(args.otw_format, sc8_scalar);
+ _mbc[mb].rx_dsps[dsp]->setup(args);
my_streamer->set_xport_chan_get_buff(chan_i, boost::bind(
&zero_copy_if::get_recv_buff, _mbc[mb].rx_dsp_xports[dsp], _1
), true /*flush*/);
@@ -447,15 +435,14 @@ tx_streamer::sptr usrp2_impl::get_tx_stream(const uhd::stream_args_t &args_){
args.otw_format = args.otw_format.empty()? "sc16" : args.otw_format;
args.channels = args.channels.empty()? std::vector<size_t>(1, 0) : args.channels;
- if (args.otw_format != "sc16"){
- throw uhd::value_error("USRP TX cannot handle requested wire format: " + args.otw_format);
- }
-
//calculate packet size
static const size_t hdr_size = 0
- + vrt::max_if_hdr_words32*sizeof(boost::uint32_t)
+ vrt_send_header_offset_words32*sizeof(boost::uint32_t)
+ + 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
+ - sizeof(vrt::if_packet_info_t().sid) //no stream id ever used
+ - sizeof(vrt::if_packet_info_t().tsi) //no int time ever used
;
const size_t bpp = _mbc[_mbc.keys().front()].tx_dsp_xport->get_send_frame_size() - hdr_size;
const size_t spp = bpp/convert::get_bytes_per_item(args.otw_format);
@@ -485,10 +472,9 @@ tx_streamer::sptr usrp2_impl::get_tx_stream(const uhd::stream_args_t &args_){
if (chan < num_chan_so_far){
const size_t dsp = chan + _mbc[mb].tx_chan_occ - num_chan_so_far;
if (not args.args.has_key("noclear")){
- _mbc[mb].tx_dsp->clear();
_io_impl->fc_mons[abs]->clear();
}
- if (args.args.has_key("underflow_policy")) _mbc[mb].tx_dsp->set_underflow_policy(args.args["underflow_policy"]);
+ _mbc[mb].tx_dsp->setup(args);
my_streamer->set_xport_chan_get_buff(chan_i, boost::bind(
&usrp2_impl::io_impl::get_send_buff, _io_impl.get(), abs, _1
));
diff --git a/host/lib/usrp/usrp2/usrp2_iface.cpp b/host/lib/usrp/usrp2/usrp2_iface.cpp
index 4830c10d9..eeba6756e 100644
--- a/host/lib/usrp/usrp2/usrp2_iface.cpp
+++ b/host/lib/usrp/usrp2/usrp2_iface.cpp
@@ -87,7 +87,7 @@ public:
//Obtain the firmware's compat number.
//Save the response compat number for communication.
//TODO can choose to reject certain older compat numbers
- usrp2_ctrl_data_t ctrl_data;
+ usrp2_ctrl_data_t ctrl_data = usrp2_ctrl_data_t();
ctrl_data.id = htonl(USRP2_CTRL_ID_WAZZUP_BRO);
ctrl_data = ctrl_send_and_recv(ctrl_data, 0, ~0);
if (ntohl(ctrl_data.id) != USRP2_CTRL_ID_WAZZUP_DUDE)
@@ -126,10 +126,9 @@ public:
bool is_device_locked(void){
boost::uint32_t lock_secs = this->get_reg<boost::uint32_t, USRP2_REG_ACTION_FW_PEEK32>(U2_FW_REG_LOCK_TIME);
boost::uint32_t lock_gpid = this->get_reg<boost::uint32_t, USRP2_REG_ACTION_FW_PEEK32>(U2_FW_REG_LOCK_GPID);
- boost::uint32_t curr_secs = this->peek32(U2_REG_TIME64_SECS_RB_IMM);
//if the difference is larger, assume not locked anymore
- if (curr_secs - lock_secs >= 3) return false;
+ if (this->get_curr_secs() - lock_secs >= 3) return false;
//otherwise only lock if the device hash is different that ours
return lock_gpid != boost::uint32_t(get_gpid());
@@ -137,12 +136,16 @@ public:
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);
+ this->get_reg<boost::uint32_t, USRP2_REG_ACTION_FW_POKE32>(U2_FW_REG_LOCK_TIME, this->get_curr_secs());
//sleep for a bit
boost::this_thread::sleep(boost::posix_time::milliseconds(1500));
}
+ boost::uint32_t get_curr_secs(void){
+ //may not be the right tick rate, but this is ok for locking purposes
+ return boost::uint32_t(this->peek32(U2_REG_TIME64_LO_RB_IMM)/100e6);
+ }
+
/***********************************************************************
* Peek and Poke
**********************************************************************/
diff --git a/host/lib/usrp/usrp2/usrp2_impl.cpp b/host/lib/usrp/usrp2/usrp2_impl.cpp
index ef7151cee..2077ab009 100644
--- a/host/lib/usrp/usrp2/usrp2_impl.cpp
+++ b/host/lib/usrp/usrp2/usrp2_impl.cpp
@@ -1,5 +1,5 @@
//
-// Copyright 2010-2011 Ettus Research LLC
+// Copyright 2010-2012 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
@@ -546,10 +546,10 @@ usrp2_impl::usrp2_impl(const device_addr_t &_device_addr){
// 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;
+ time64_rb_bases.rb_hi_now = U2_REG_TIME64_HI_RB_IMM;
+ time64_rb_bases.rb_lo_now = U2_REG_TIME64_LO_RB_IMM;
+ time64_rb_bases.rb_hi_pps = U2_REG_TIME64_HI_RB_PPS;
+ time64_rb_bases.rb_lo_pps = U2_REG_TIME64_LO_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
);
@@ -572,6 +572,13 @@ usrp2_impl::usrp2_impl(const device_addr_t &_device_addr){
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 user-defined control objects
+ ////////////////////////////////////////////////////////////////////
+ _mbc[mb].user = user_settings_core_200::make(_mbc[mb].iface, U2_REG_SR_ADDR(SR_USER_REGS));
+ _tree->create<user_settings_core_200::user_reg_t>(mb_path / "user/regs")
+ .subscribe(boost::bind(&user_settings_core_200::set_reg, _mbc[mb].user, _1));
+
////////////////////////////////////////////////////////////////
// create dboard control objects
////////////////////////////////////////////////////////////////
diff --git a/host/lib/usrp/usrp2/usrp2_impl.hpp b/host/lib/usrp/usrp2/usrp2_impl.hpp
index 278dc713e..882a61f80 100644
--- a/host/lib/usrp/usrp2/usrp2_impl.hpp
+++ b/host/lib/usrp/usrp2/usrp2_impl.hpp
@@ -1,5 +1,5 @@
//
-// Copyright 2010-2011 Ettus Research LLC
+// Copyright 2010-2012 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,6 +26,7 @@
#include "rx_dsp_core_200.hpp"
#include "tx_dsp_core_200.hpp"
#include "time64_core_200.hpp"
+#include "user_settings_core_200.hpp"
#include <uhd/property_tree.hpp>
#include <uhd/usrp/gps_ctrl.hpp>
#include <uhd/device.hpp>
@@ -91,6 +92,7 @@ private:
std::vector<boost::weak_ptr<uhd::tx_streamer> > tx_streamers;
tx_dsp_core_200::sptr tx_dsp;
time64_core_200::sptr time64;
+ user_settings_core_200::sptr user;
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;
diff --git a/host/lib/usrp/usrp2/usrp2_regs.hpp b/host/lib/usrp/usrp2/usrp2_regs.hpp
index 179a930c6..e14798ecb 100644
--- a/host/lib/usrp/usrp2/usrp2_regs.hpp
+++ b/host/lib/usrp/usrp2/usrp2_regs.hpp
@@ -1,5 +1,5 @@
//
-// Copyright 2010-2011 Ettus Research LLC
+// Copyright 2010-2012 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 @@
#define SR_SIMTIMER 8 // 2
#define SR_TIME64 10 // 6
#define SR_BUF_POOL 16 // 4
-
+#define SR_USER_REGS 20 // 2
#define SR_RX_FRONT 24 // 5
#define SR_RX_CTRL0 32 // 9
#define SR_RX_DSP0 48 // 7
@@ -97,11 +97,11 @@
////////////////////////////////////////////////
#define U2_REG_STATUS READBACK_BASE + 4*8
#define U2_REG_GPIO_RB READBACK_BASE + 4*9
-#define U2_REG_TIME64_SECS_RB_IMM READBACK_BASE + 4*10
-#define U2_REG_TIME64_TICKS_RB_IMM READBACK_BASE + 4*11
+#define U2_REG_TIME64_HI_RB_IMM READBACK_BASE + 4*10
+#define U2_REG_TIME64_LO_RB_IMM READBACK_BASE + 4*11
#define U2_REG_COMPAT_NUM_RB READBACK_BASE + 4*12
#define U2_REG_IRQ_RB READBACK_BASE + 4*13
-#define U2_REG_TIME64_SECS_RB_PPS READBACK_BASE + 4*14
-#define U2_REG_TIME64_TICKS_RB_PPS READBACK_BASE + 4*15
+#define U2_REG_TIME64_HI_RB_PPS READBACK_BASE + 4*14
+#define U2_REG_TIME64_LO_RB_PPS READBACK_BASE + 4*15
#endif /* INCLUDED_USRP2_REGS_HPP */
diff --git a/host/tests/convert_test.cpp b/host/tests/convert_test.cpp
index 1a5d30080..6b0ae53a9 100644
--- a/host/tests/convert_test.cpp
+++ b/host/tests/convert_test.cpp
@@ -1,5 +1,5 @@
//
-// Copyright 2011-2011 Ettus Research LLC
+// Copyright 2011-2012 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
@@ -31,8 +31,9 @@ typedef std::complex<boost::int16_t> sc16_t;
typedef std::complex<float> fc32_t;
typedef std::complex<double> fc64_t;
-#define MY_CHECK_CLOSE(a, b, f) if ((std::abs(a) > (f))) \
- BOOST_CHECK_CLOSE_FRACTION(a, b, f)
+#define MY_CHECK_CLOSE(a, b, f) { \
+ BOOST_CHECK_MESSAGE(std::abs((a)-(b)) < f, "\n\t" << #a << " (" << (a) << ") error " << #b << " (" << (b) << ")"); \
+}
/***********************************************************************
* Loopback runner:
@@ -67,13 +68,13 @@ template <typename Range> static void loopback(
* Test short conversion
**********************************************************************/
static void test_convert_types_sc16(
- size_t nsamps, convert::id_type &id
+ size_t nsamps, convert::id_type &id, const int extra_div = 1
){
//fill the input samples
std::vector<sc16_t> input(nsamps), output(nsamps);
BOOST_FOREACH(sc16_t &in, input) in = sc16_t(
- std::rand()-(RAND_MAX/2),
- std::rand()-(RAND_MAX/2)
+ short(((std::rand()/double(RAND_MAX/2)) - 1)*32767/extra_div),
+ short(((std::rand()/double(RAND_MAX/2)) - 1)*32767/extra_div)
);
//run the loopback and test
@@ -116,15 +117,15 @@ BOOST_AUTO_TEST_CASE(test_convert_types_le_sc16){
**********************************************************************/
template <typename data_type>
static void test_convert_types_for_floats(
- size_t nsamps, convert::id_type &id
+ size_t nsamps, convert::id_type &id, const double extra_scale = 1.0
){
typedef typename data_type::value_type value_type;
//fill the input samples
std::vector<data_type> input(nsamps), output(nsamps);
BOOST_FOREACH(data_type &in, input) in = data_type(
- (std::rand()/value_type(RAND_MAX/2)) - 1,
- (std::rand()/value_type(RAND_MAX/2)) - 1
+ ((std::rand()/value_type(RAND_MAX/2)) - 1)*float(extra_scale),
+ ((std::rand()/value_type(RAND_MAX/2)) - 1)*float(extra_scale)
);
//run the loopback and test
@@ -134,8 +135,8 @@ static void test_convert_types_for_floats(
std::swap(out_id.num_inputs, out_id.num_outputs);
loopback(nsamps, in_id, out_id, input, output);
for (size_t i = 0; i < nsamps; i++){
- MY_CHECK_CLOSE(input[i].real(), output[i].real(), value_type(0.01));
- MY_CHECK_CLOSE(input[i].imag(), output[i].imag(), value_type(0.01));
+ MY_CHECK_CLOSE(input[i].real(), output[i].real(), value_type(1./32767));
+ MY_CHECK_CLOSE(input[i].imag(), output[i].imag(), value_type(1./32767));
}
}
@@ -280,3 +281,63 @@ BOOST_AUTO_TEST_CASE(test_convert_types_sc16_to_fc32){
MY_CHECK_CLOSE(input[i].imag()/float(32767), output[i].imag(), float(0.01));
}
}
+
+/***********************************************************************
+ * Test sc8 conversions
+ **********************************************************************/
+BOOST_AUTO_TEST_CASE(test_convert_types_fc64_and_sc8){
+ convert::id_type id;
+ id.input_format = "fc64";
+ id.num_inputs = 1;
+ id.num_outputs = 1;
+
+ //try various lengths to test edge cases
+ id.output_format = "sc8_item32_le";
+ for (size_t nsamps = 1; nsamps < 16; nsamps++){
+ test_convert_types_for_floats<fc64_t>(nsamps, id, 1./256);
+ }
+
+ //try various lengths to test edge cases
+ id.output_format = "sc8_item32_be";
+ for (size_t nsamps = 1; nsamps < 16; nsamps++){
+ test_convert_types_for_floats<fc64_t>(nsamps, id, 1./256);
+ }
+}
+
+BOOST_AUTO_TEST_CASE(test_convert_types_fc32_and_sc8){
+ convert::id_type id;
+ id.input_format = "fc32";
+ id.num_inputs = 1;
+ id.num_outputs = 1;
+
+ //try various lengths to test edge cases
+ id.output_format = "sc8_item32_le";
+ for (size_t nsamps = 1; nsamps < 16; nsamps++){
+ test_convert_types_for_floats<fc32_t>(nsamps, id, 1./256);
+ }
+
+ //try various lengths to test edge cases
+ id.output_format = "sc8_item32_be";
+ for (size_t nsamps = 1; nsamps < 16; nsamps++){
+ test_convert_types_for_floats<fc32_t>(nsamps, id, 1./256);
+ }
+}
+
+BOOST_AUTO_TEST_CASE(test_convert_types_sc16_and_sc8){
+ convert::id_type id;
+ id.input_format = "sc16";
+ id.num_inputs = 1;
+ id.num_outputs = 1;
+
+ //try various lengths to test edge cases
+ id.output_format = "sc8_item32_le";
+ for (size_t nsamps = 1; nsamps < 16; nsamps++){
+ test_convert_types_sc16(nsamps, id, 256);
+ }
+
+ //try various lengths to test edge cases
+ id.output_format = "sc8_item32_be";
+ for (size_t nsamps = 1; nsamps < 16; nsamps++){
+ test_convert_types_sc16(nsamps, id, 256);
+ }
+}
diff --git a/host/tests/sph_recv_test.cpp b/host/tests/sph_recv_test.cpp
index 85d06aa0d..9b45d7016 100644
--- a/host/tests/sph_recv_test.cpp
+++ b/host/tests/sph_recv_test.cpp
@@ -1,5 +1,5 @@
//
-// Copyright 2011 Ettus Research LLC
+// Copyright 2011-2012 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
@@ -159,7 +159,7 @@ BOOST_AUTO_TEST_CASE(test_sph_recv_one_channel_normal){
BOOST_CHECK_EQUAL(metadata.error_code, uhd::rx_metadata_t::ERROR_CODE_NONE);
BOOST_CHECK(not metadata.more_fragments);
BOOST_CHECK(metadata.has_time_spec);
- BOOST_CHECK_TS_CLOSE(metadata.time_spec, uhd::time_spec_t(0, num_accum_samps, SAMP_RATE));
+ BOOST_CHECK_TS_CLOSE(metadata.time_spec, uhd::time_spec_t::from_ticks(num_accum_samps, SAMP_RATE));
BOOST_CHECK_EQUAL(num_samps_ret, 10 + i%10);
num_accum_samps += num_samps_ret;
}
@@ -232,14 +232,14 @@ BOOST_AUTO_TEST_CASE(test_sph_recv_one_channel_sequence_error){
if (i == NUM_PKTS_TO_TEST/2){
//must get the soft overflow here
BOOST_REQUIRE(metadata.error_code == uhd::rx_metadata_t::ERROR_CODE_OVERFLOW);
- BOOST_CHECK_TS_CLOSE(metadata.time_spec, uhd::time_spec_t(0, num_accum_samps, SAMP_RATE));
+ BOOST_CHECK_TS_CLOSE(metadata.time_spec, uhd::time_spec_t::from_ticks(num_accum_samps, SAMP_RATE));
num_accum_samps += 10 + i%10;
}
else{
BOOST_CHECK_EQUAL(metadata.error_code, uhd::rx_metadata_t::ERROR_CODE_NONE);
BOOST_CHECK(not metadata.more_fragments);
BOOST_CHECK(metadata.has_time_spec);
- BOOST_CHECK_TS_CLOSE(metadata.time_spec, uhd::time_spec_t(0, num_accum_samps, SAMP_RATE));
+ BOOST_CHECK_TS_CLOSE(metadata.time_spec, uhd::time_spec_t::from_ticks(num_accum_samps, SAMP_RATE));
BOOST_CHECK_EQUAL(num_samps_ret, 10 + i%10);
num_accum_samps += num_samps_ret;
}
@@ -323,7 +323,7 @@ BOOST_AUTO_TEST_CASE(test_sph_recv_one_channel_inline_message){
BOOST_CHECK_EQUAL(metadata.error_code, uhd::rx_metadata_t::ERROR_CODE_NONE);
BOOST_CHECK(not metadata.more_fragments);
BOOST_CHECK(metadata.has_time_spec);
- BOOST_CHECK_TS_CLOSE(metadata.time_spec, uhd::time_spec_t(0, num_accum_samps, SAMP_RATE));
+ BOOST_CHECK_TS_CLOSE(metadata.time_spec, uhd::time_spec_t::from_ticks(num_accum_samps, SAMP_RATE));
BOOST_CHECK_EQUAL(num_samps_ret, 10 + i%10);
num_accum_samps += num_samps_ret;
if (i == NUM_PKTS_TO_TEST/2){
@@ -332,7 +332,7 @@ BOOST_AUTO_TEST_CASE(test_sph_recv_one_channel_inline_message){
);
std::cout << "metadata.error_code " << metadata.error_code << std::endl;
BOOST_REQUIRE(metadata.error_code == uhd::rx_metadata_t::ERROR_CODE_OVERFLOW);
- BOOST_CHECK_TS_CLOSE(metadata.time_spec, uhd::time_spec_t(0, num_accum_samps, SAMP_RATE));
+ BOOST_CHECK_TS_CLOSE(metadata.time_spec, uhd::time_spec_t::from_ticks(num_accum_samps, SAMP_RATE));
BOOST_CHECK_EQUAL(overflow_handler.num_overflow, size_t(1));
}
}
@@ -414,7 +414,7 @@ BOOST_AUTO_TEST_CASE(test_sph_recv_multi_channel_normal){
BOOST_CHECK_EQUAL(metadata.error_code, uhd::rx_metadata_t::ERROR_CODE_NONE);
BOOST_CHECK(not metadata.more_fragments);
BOOST_CHECK(metadata.has_time_spec);
- BOOST_CHECK_TS_CLOSE(metadata.time_spec, uhd::time_spec_t(0, num_accum_samps, SAMP_RATE));
+ BOOST_CHECK_TS_CLOSE(metadata.time_spec, uhd::time_spec_t::from_ticks(num_accum_samps, SAMP_RATE));
BOOST_CHECK_EQUAL(num_samps_ret, 10 + i%10);
num_accum_samps += num_samps_ret;
}
@@ -500,14 +500,14 @@ BOOST_AUTO_TEST_CASE(test_sph_recv_multi_channel_sequence_error){
if (i == NUM_PKTS_TO_TEST/2){
//must get the soft overflow here
BOOST_REQUIRE(metadata.error_code == uhd::rx_metadata_t::ERROR_CODE_OVERFLOW);
- BOOST_CHECK_TS_CLOSE(metadata.time_spec, uhd::time_spec_t(0, num_accum_samps, SAMP_RATE));
+ BOOST_CHECK_TS_CLOSE(metadata.time_spec, uhd::time_spec_t::from_ticks(num_accum_samps, SAMP_RATE));
num_accum_samps += 10 + i%10;
}
else{
BOOST_CHECK_EQUAL(metadata.error_code, uhd::rx_metadata_t::ERROR_CODE_NONE);
BOOST_CHECK(not metadata.more_fragments);
BOOST_CHECK(metadata.has_time_spec);
- BOOST_CHECK_TS_CLOSE(metadata.time_spec, uhd::time_spec_t(0, num_accum_samps, SAMP_RATE));
+ BOOST_CHECK_TS_CLOSE(metadata.time_spec, uhd::time_spec_t::from_ticks(num_accum_samps, SAMP_RATE));
BOOST_CHECK_EQUAL(num_samps_ret, 10 + i%10);
num_accum_samps += num_samps_ret;
}
@@ -593,7 +593,7 @@ BOOST_AUTO_TEST_CASE(test_sph_recv_multi_channel_time_error){
BOOST_CHECK_EQUAL(metadata.error_code, uhd::rx_metadata_t::ERROR_CODE_NONE);
BOOST_CHECK(not metadata.more_fragments);
BOOST_CHECK(metadata.has_time_spec);
- BOOST_CHECK_TS_CLOSE(metadata.time_spec, uhd::time_spec_t(0, num_accum_samps, SAMP_RATE));
+ BOOST_CHECK_TS_CLOSE(metadata.time_spec, uhd::time_spec_t::from_ticks(num_accum_samps, SAMP_RATE));
BOOST_CHECK_EQUAL(num_samps_ret, 10 + i%10);
num_accum_samps += num_samps_ret;
if (i == NUM_PKTS_TO_TEST/2){
@@ -677,7 +677,7 @@ BOOST_AUTO_TEST_CASE(test_sph_recv_multi_channel_fragment){
);
BOOST_CHECK_EQUAL(metadata.error_code, uhd::rx_metadata_t::ERROR_CODE_NONE);
BOOST_CHECK(metadata.has_time_spec);
- BOOST_CHECK_TS_CLOSE(metadata.time_spec, uhd::time_spec_t(0, num_accum_samps, SAMP_RATE));
+ BOOST_CHECK_TS_CLOSE(metadata.time_spec, uhd::time_spec_t::from_ticks(num_accum_samps, SAMP_RATE));
BOOST_CHECK_EQUAL(num_samps_ret, 10);
num_accum_samps += num_samps_ret;
@@ -690,7 +690,7 @@ BOOST_AUTO_TEST_CASE(test_sph_recv_multi_channel_fragment){
BOOST_CHECK(not metadata.more_fragments);
BOOST_CHECK_EQUAL(metadata.fragment_offset, 10);
BOOST_CHECK(metadata.has_time_spec);
- BOOST_CHECK_TS_CLOSE(metadata.time_spec, uhd::time_spec_t(0, num_accum_samps, SAMP_RATE));
+ BOOST_CHECK_TS_CLOSE(metadata.time_spec, uhd::time_spec_t::from_ticks(num_accum_samps, SAMP_RATE));
BOOST_CHECK_EQUAL(num_samps_ret, i%10);
num_accum_samps += num_samps_ret;
}
diff --git a/host/tests/sph_send_test.cpp b/host/tests/sph_send_test.cpp
index 25a3f97ee..c31399d12 100644
--- a/host/tests/sph_send_test.cpp
+++ b/host/tests/sph_send_test.cpp
@@ -1,5 +1,5 @@
//
-// Copyright 2011 Ettus Research LLC
+// Copyright 2011-2012 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
@@ -136,9 +136,7 @@ BOOST_AUTO_TEST_CASE(test_sph_send_one_channel_one_packet_mode){
std::cout << "data check " << i << std::endl;
dummy_send_xport.pop_front_packet(ifpi);
BOOST_CHECK_EQUAL(ifpi.num_payload_words32, 10+i%10);
- BOOST_CHECK(ifpi.has_tsi);
BOOST_CHECK(ifpi.has_tsf);
- BOOST_CHECK_EQUAL(ifpi.tsi, 0);
BOOST_CHECK_EQUAL(ifpi.tsf, num_accum_samps*TICK_RATE/SAMP_RATE);
BOOST_CHECK_EQUAL(ifpi.sob, i == 0);
BOOST_CHECK_EQUAL(ifpi.eob, i == NUM_PKTS_TO_TEST-1);
@@ -191,9 +189,7 @@ BOOST_AUTO_TEST_CASE(test_sph_send_one_channel_full_buffer_mode){
std::cout << "data check " << i << std::endl;
dummy_send_xport.pop_front_packet(ifpi);
BOOST_CHECK_EQUAL(ifpi.num_payload_words32, 20);
- BOOST_CHECK(ifpi.has_tsi);
BOOST_CHECK(ifpi.has_tsf);
- BOOST_CHECK_EQUAL(ifpi.tsi, 0);
BOOST_CHECK_EQUAL(ifpi.tsf, num_accum_samps*TICK_RATE/SAMP_RATE);
BOOST_CHECK_EQUAL(ifpi.sob, i == 0);
BOOST_CHECK_EQUAL(ifpi.eob, i == NUM_PKTS_TO_TEST-1);
diff --git a/host/tests/time_spec_test.cpp b/host/tests/time_spec_test.cpp
index 467da5c18..102b7cda3 100644
--- a/host/tests/time_spec_test.cpp
+++ b/host/tests/time_spec_test.cpp
@@ -1,5 +1,5 @@
//
-// Copyright 2010-2011 Ettus Research LLC
+// Copyright 2010-2012 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
@@ -54,11 +54,11 @@ BOOST_AUTO_TEST_CASE(test_time_spec_parts){
BOOST_CHECK_EQUAL(uhd::time_spec_t(1.1).get_full_secs(), 1);
BOOST_CHECK_CLOSE(uhd::time_spec_t(1.1).get_frac_secs(), 0.1, 0.001);
- BOOST_CHECK_EQUAL(uhd::time_spec_t(1.1).get_tick_count(100), 10);
+ BOOST_CHECK_EQUAL(uhd::time_spec_t(1.1).to_ticks(100), 110);
BOOST_CHECK_EQUAL(uhd::time_spec_t(-1.1).get_full_secs(), -2);
BOOST_CHECK_CLOSE(uhd::time_spec_t(-1.1).get_frac_secs(), 0.9, 0.001);
- BOOST_CHECK_EQUAL(uhd::time_spec_t(-1.1).get_tick_count(100), 90);
+ BOOST_CHECK_EQUAL(uhd::time_spec_t(-1.1).to_ticks(100), -110);
}
BOOST_AUTO_TEST_CASE(test_time_spec_get_system_time){
diff --git a/host/usrp_e_utils/usrp-e-loopback.cpp b/host/usrp_e_utils/usrp-e-loopback.cpp
index 5b289c648..d4220adc3 100644
--- a/host/usrp_e_utils/usrp-e-loopback.cpp
+++ b/host/usrp_e_utils/usrp-e-loopback.cpp
@@ -261,8 +261,7 @@ int main(int argc, char *argv[]){
poke16(E100_REG_MISC_XFER_RATE, (1<<8) | (1<<9));
//clear FIFO state in FPGA and kernel
- poke32(E100_REG_CLEAR_RX, 0);
- poke32(E100_REG_CLEAR_TX, 0);
+ poke32(E100_REG_CLEAR_FIFO, 0);
::close(fp);
if ((fp = ::open("/dev/usrp_e0", O_RDWR)) < 0){
std::cerr << "Open failed" << std::endl;
diff --git a/images/README b/images/README.txt
index 2f9c6a95e..2f9c6a95e 100644
--- a/images/README
+++ b/images/README.txt