diff options
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 ®){ + _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 ®) = 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 |