summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJosh Blum <josh@joshknows.com>2010-04-28 16:35:22 -0700
committerJosh Blum <josh@joshknows.com>2010-04-28 16:35:22 -0700
commita7c230cb1f97b452da027d5baa71891f2066d430 (patch)
tree2b6188648a5ba9091459108f93b5aef3a6a87096
parent04dae4bf6b11b5aad383f95be6a77863a7c2f6ec (diff)
downloaduhd-a7c230cb1f97b452da027d5baa71891f2066d430.tar.gz
uhd-a7c230cb1f97b452da027d5baa71891f2066d430.tar.bz2
uhd-a7c230cb1f97b452da027d5baa71891f2066d430.zip
Added reload flag to the stream cmd.
This reloads the last command to handle continuous streaming in hardware. Moved rx control register setup and stream command issuing to the host.
-rw-r--r--firmware/microblaze/apps/txrx_uhd.c120
-rw-r--r--firmware/microblaze/lib/banal.c18
-rw-r--r--firmware/microblaze/lib/banal.h3
-rw-r--r--firmware/microblaze/lib/memory_map.h4
-rw-r--r--firmware/microblaze/lib/u2_init.c4
-rw-r--r--fpga/usrp2/vrt/vita_rx_control.v24
-rw-r--r--host/lib/usrp/usrp2/dsp_impl.cpp3
-rw-r--r--host/lib/usrp/usrp2/fw_common.h14
-rw-r--r--host/lib/usrp/usrp2/io_impl.cpp22
-rw-r--r--host/lib/usrp/usrp2/mboard_impl.cpp59
-rw-r--r--host/lib/usrp/usrp2/usrp2_regs.hpp21
11 files changed, 83 insertions, 209 deletions
diff --git a/firmware/microblaze/apps/txrx_uhd.c b/firmware/microblaze/apps/txrx_uhd.c
index 8ff3b8c58..d5b400e0c 100644
--- a/firmware/microblaze/apps/txrx_uhd.c
+++ b/firmware/microblaze/apps/txrx_uhd.c
@@ -126,14 +126,7 @@ dbsm_t dsp_rx_sm; // the state machine
// The mac address of the host we're sending to.
eth_mac_addr_t host_mac_addr;
-//controls continuous streaming...
-static bool auto_reload_command = false;
-static size_t streaming_items_per_frame = 0;
-static int streaming_frame_count = 0;
-#define FRAMES_PER_CMD 2
-
static void setup_network(void);
-static void setup_vrt(void);
// ----------------------------------------------------------------
// the fast-path setup global variables
@@ -154,9 +147,6 @@ void handle_udp_data_packet(
struct socket_address src, struct socket_address dst,
unsigned char *payload, int payload_len
){
- //store the 2nd word as the following:
- streaming_items_per_frame = ((uint32_t *)payload)[1];
-
//its a tiny payload, load the fast-path variables
fp_mac_addr_src = *ethernet_mac_addr();
arp_cache_lookup_mac(&src.addr, &fp_mac_addr_dst);
@@ -177,23 +167,12 @@ void handle_udp_data_packet(
//setup network and vrt
setup_network();
- setup_vrt();
// kick off the state machine
dbsm_start(&dsp_rx_sm);
}
-static void inline issue_stream_command(size_t nsamps, bool now, bool chain, uint32_t secs, uint32_t ticks, bool start){
- //printf("Stream cmd: nsamps %d, now %d, chain %d, secs %u, ticks %u\n", (int)nsamps, now, chain, secs, ticks);
- sr_rx_ctrl->cmd = MK_RX_CMD(nsamps, now, chain);
-
- if (start) dbsm_start(&dsp_rx_sm);
-
- sr_rx_ctrl->time_secs = secs;
- sr_rx_ctrl->time_ticks = ticks; // enqueue command
-}
-
#define OTW_GPIO_BANK_TO_NUM(bank) \
(((bank) == USRP2_DIR_RX)? (GPIO_RX_BANK) : (GPIO_TX_BANK))
@@ -304,72 +283,6 @@ void handle_udp_ctrl_packet(
break;
/*******************************************************************
- * Streaming
- ******************************************************************/
- case USRP2_CTRL_ID_SEND_STREAM_COMMAND_FOR_ME_BRO:{
-
- //issue two commands and set the auto-reload flag
- if (ctrl_data_in->data.stream_cmd.continuous){
- printf("Setting up continuous streaming...\n");
- printf("items per frame: %d\n", (int)streaming_items_per_frame);
- hal_set_leds(LED_A, LEDS_SW);
- auto_reload_command = true;
- streaming_frame_count = FRAMES_PER_CMD;
-
- issue_stream_command(
- streaming_items_per_frame * FRAMES_PER_CMD,
- (ctrl_data_in->data.stream_cmd.now == 0)? false : true, //now
- true, //chain
- ctrl_data_in->data.stream_cmd.secs,
- ctrl_data_in->data.stream_cmd.ticks,
- true //start
- );
-
- issue_stream_command(
- streaming_items_per_frame * FRAMES_PER_CMD,
- true, //now
- true, //chain
- 0, 0, //time does not matter
- false
- );
-
- }
-
- //issue regular stream commands (split commands if too large)
- else{
- hal_set_leds(0, LEDS_SW);
- auto_reload_command = false;
- size_t num_samps = ctrl_data_in->data.stream_cmd.num_samps;
- if (num_samps == 0) num_samps = 1; //FIXME hack, zero is used when stopping continuous streaming but it somehow makes it inifinite
-
- bool chain = num_samps > MAX_SAMPLES_PER_CMD;
- issue_stream_command(
- (chain)? streaming_items_per_frame : num_samps, //nsamps
- (ctrl_data_in->data.stream_cmd.now == 0)? false : true, //now
- (ctrl_data_in->data.stream_cmd.chain == 0)? chain : true, //chain
- ctrl_data_in->data.stream_cmd.secs,
- ctrl_data_in->data.stream_cmd.ticks,
- false
- );
-
- //handle rest of the samples that did not fit into one cmd
- while(chain){
- num_samps -= MAX_SAMPLES_PER_CMD;
- chain = num_samps > MAX_SAMPLES_PER_CMD;
- issue_stream_command(
- (chain)? streaming_items_per_frame : num_samps, //nsamps
- true, //now
- (ctrl_data_in->data.stream_cmd.chain == 0)? chain : true, //chain
- 0, 0, //time does not matter
- false
- );
- }
- }
- ctrl_data_out.id = USRP2_CTRL_ID_GOT_THAT_STREAM_COMMAND_DUDE;
- break;
- }
-
- /*******************************************************************
* Peek and Poke Register
******************************************************************/
case USRP2_CTRL_ID_POKE_THIS_REGISTER_FOR_ME_BRO:
@@ -463,25 +376,6 @@ eth_pkt_inspector(dbsm_t *sm, int bufno)
//------------------------------------------------------------------
-static bool vrt_has_trailer(void){
- return USRP2_HOST_RX_VRT_TRAILER_WORDS32 > 0;
-}
-
-static void setup_vrt(void){
- // setup RX DSP regs
- sr_rx_ctrl->nsamples_per_pkt = streaming_items_per_frame;
- sr_rx_ctrl->nchannels = 1;
- sr_rx_ctrl->clear_overrun = 1; // reset
- sr_rx_ctrl->vrt_header = (0
- | VRTH_PT_IF_DATA_WITH_SID
- | (vrt_has_trailer()? VRTH_HAS_TRAILER : 0)
- | VRTH_TSI_OTHER
- | VRTH_TSF_SAMPLE_CNT
- );
- sr_rx_ctrl->vrt_stream_id = 0;
- sr_rx_ctrl->vrt_trailer = 0;
-}
-
/*
* 1's complement sum for IP and UDP headers
*
@@ -554,13 +448,6 @@ fw_sets_seqno_inspector(dbsm_t *sm, int buf_this) // returns false
buff->control_word = MK_RX_CTRL_WORD(vrt_len);
buff->vrt_header[0] = (buff->vrt_header[0] & ~VRTH_PKT_SIZE_MASK) | (vrt_len & VRTH_PKT_SIZE_MASK);
- // queue up another rx command when required
- if (auto_reload_command && --streaming_frame_count == 0){
- streaming_frame_count = FRAMES_PER_CMD;
- sr_rx_ctrl->time_secs = 0;
- sr_rx_ctrl->time_ticks = 0; //enqueue last command
- }
-
return false; // we didn't handle the packet
}
@@ -662,13 +549,6 @@ hal_gpio_set_sels(GPIO_RX_BANK, "aaaaaaaaaaaaaaaa");
// FIXME Figure out how to handle this robustly.
// Any buffers that are emptying should be allowed to drain...
- if (auto_reload_command){
- // restart_streaming();
- // FIXME report error
- }
- else {
- // FIXME report error
- }
putchar('O');
}
}
diff --git a/firmware/microblaze/lib/banal.c b/firmware/microblaze/lib/banal.c
index 23f5f3b8a..42937957f 100644
--- a/firmware/microblaze/lib/banal.c
+++ b/firmware/microblaze/lib/banal.c
@@ -29,21 +29,3 @@ get_uint64(const unsigned char *s)
{
return (((uint64_t)get_uint32(s)) << 32) | get_uint32(s+4);
}
-
-uint32_t
-divide_uint64(uint64_t dividend, uint32_t divisor)
-{
- uint32_t result = 0;
- uint64_t dividend_ = 0;
- for(int i = 31; i >= 0; i--){
- //approximate the divisor with the ith result bit set
- uint64_t tmp = dividend_;
- tmp += (uint64_t)divisor << i;
- //set the ith result bit if the approximation is less
- if (tmp <= dividend){
- dividend_ = tmp;
- result |= 1 << i;
- }
- }
- return result;
-}
diff --git a/firmware/microblaze/lib/banal.h b/firmware/microblaze/lib/banal.h
index 6d9420602..7b3c71a20 100644
--- a/firmware/microblaze/lib/banal.h
+++ b/firmware/microblaze/lib/banal.h
@@ -87,7 +87,4 @@ get_int64(const unsigned char *s)
void
print_ip(struct ip_addr ip);
-uint32_t
-divide_uint64(uint64_t dividend, uint32_t divisor);
-
#endif /* INCLUDED_BANAL_H */
diff --git a/firmware/microblaze/lib/memory_map.h b/firmware/microblaze/lib/memory_map.h
index fed1e5259..cdf3dd338 100644
--- a/firmware/microblaze/lib/memory_map.h
+++ b/firmware/microblaze/lib/memory_map.h
@@ -525,10 +525,6 @@ typedef struct {
volatile uint32_t pad[7]; // Make each structure 16 elements long
} sr_rx_ctrl_t;
-#define MAX_SAMPLES_PER_CMD 0x3fffffff
-#define MK_RX_CMD(nsamples, now, chain) \
- ((((now) & 0x1) << 31) | (((chain) & 0x1) << 30) | ((nsamples) & 0x3fffffff))
-
#define sr_rx_ctrl ((sr_rx_ctrl_t *) _SR_ADDR(SR_RX_CTRL))
// --- dsp rx regs ---
diff --git a/firmware/microblaze/lib/u2_init.c b/firmware/microblaze/lib/u2_init.c
index 399d834cb..40237ba87 100644
--- a/firmware/microblaze/lib/u2_init.c
+++ b/firmware/microblaze/lib/u2_init.c
@@ -50,8 +50,8 @@ u2_init(void)
hal_gpio_set_ddr(GPIO_TX_BANK, 0x0000, 0xffff);
hal_gpio_set_ddr(GPIO_RX_BANK, 0x0000, 0xffff);
- hal_gpio_write(GPIO_TX_BANK, 0x0000, 0xffff); // init s/w output value to zero
- hal_gpio_write(GPIO_RX_BANK, 0x0000, 0xffff);
+ //hal_gpio_write(GPIO_TX_BANK, 0x0000, 0xffff); // init s/w output value to zero
+ //hal_gpio_write(GPIO_RX_BANK, 0x0000, 0xffff);
dsp_rx_regs->gpio_stream_enable = 0; // I, Q LSBs come from DSP
diff --git a/fpga/usrp2/vrt/vita_rx_control.v b/fpga/usrp2/vrt/vita_rx_control.v
index 669b8299d..742dd47e0 100644
--- a/fpga/usrp2/vrt/vita_rx_control.v
+++ b/fpga/usrp2/vrt/vita_rx_control.v
@@ -31,13 +31,13 @@ module vita_rx_control
wire [63:0] rcvtime_pre;
reg [63:0] rcvtime;
- wire [29:0] numlines_pre;
- wire send_imm_pre, chain_pre;
- reg send_imm, chain;
+ wire [28:0] numlines_pre;
+ wire send_imm_pre, chain_pre, reload_pre;
+ reg send_imm, chain, reload;
wire full_ctrl, read_ctrl, empty_ctrl, write_ctrl;
reg sc_pre2;
wire [33:0] fifo_line;
- reg [29:0] lines_left;
+ reg [28:0] lines_left, lines_total;
reg [2:0] ibs_state;
wire now, early, late;
wire sample_fifo_in_rdy;
@@ -67,7 +67,7 @@ module vita_rx_control
shortfifo #(.WIDTH(96)) commandfifo
(.clk(clk),.rst(reset),.clear(clear_int),
.datain({new_command,new_time}), .write(write_ctrl&~full_ctrl), .full(full_ctrl),
- .dataout({send_imm_pre,chain_pre,numlines_pre,rcvtime_pre}),
+ .dataout({send_imm_pre,chain_pre,reload_pre,numlines_pre,rcvtime_pre}),
.read(read_ctrl), .empty(empty_ctrl),
.occupied(command_queue_len), .space() );
@@ -98,7 +98,7 @@ module vita_rx_control
.src_rdy_o(sample_fifo_src_rdy_o), .dst_rdy_i(sample_fifo_dst_rdy_i),
.space(), .occupied() );
- // Inband Signalling State Machine
+ // Inband Signallling State Machine
time_compare
time_compare (.time_now(vita_time), .trigger_time(rcvtime), .now(now), .early(early), .late(late));
@@ -111,9 +111,11 @@ module vita_rx_control
begin
ibs_state <= IBS_IDLE;
lines_left <= 0;
+ lines_total <= 0;
rcvtime <= 0;
send_imm <= 0;
chain <= 0;
+ reload <= 0;
end
else
case(ibs_state)
@@ -121,10 +123,12 @@ module vita_rx_control
if(~empty_ctrl)
begin
lines_left <= numlines_pre;
+ lines_total <= numlines_pre;
rcvtime <= rcvtime_pre;
ibs_state <= IBS_WAITING;
send_imm <= send_imm_pre;
chain <= chain_pre;
+ reload <= reload_pre;
end
IBS_WAITING :
if(go_now)
@@ -141,14 +145,21 @@ module vita_rx_control
if(lines_left == 1)
if(~chain)
ibs_state <= IBS_IDLE;
+ else if(empty_ctrl & reload)
+ begin
+ ibs_state <= IBS_RUNNING;
+ lines_left <= lines_total;
+ end
else if(empty_ctrl)
ibs_state <= IBS_BROKENCHAIN;
else
begin
lines_left <= numlines_pre;
+ lines_total <= numlines_pre;
rcvtime <= rcvtime_pre;
send_imm <= send_imm_pre;
chain <= chain_pre;
+ reload <= reload_pre;
if(numlines_pre == 0) // If we are told to stop here
ibs_state <= IBS_IDLE;
else
@@ -178,3 +189,4 @@ module vita_rx_control
{ 2'b0, overrun, chain_pre, sample_fifo_in_rdy, attempt_sample_write, sample_fifo_src_rdy_o,sample_fifo_dst_rdy_i} };
endmodule // rx_control
+
diff --git a/host/lib/usrp/usrp2/dsp_impl.cpp b/host/lib/usrp/usrp2/dsp_impl.cpp
index 84314a656..bd61ac376 100644
--- a/host/lib/usrp/usrp2/dsp_impl.cpp
+++ b/host/lib/usrp/usrp2/dsp_impl.cpp
@@ -77,9 +77,6 @@ void usrp2_impl::init_ddc_config(void){
_ddc_decim = default_decim;
_ddc_freq = 0;
update_ddc_config();
-
- //initial command that kills streaming (in case if was left on)
- issue_ddc_stream_cmd(stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS);
}
void usrp2_impl::update_ddc_config(void){
diff --git a/host/lib/usrp/usrp2/fw_common.h b/host/lib/usrp/usrp2/fw_common.h
index e80001ff2..f28013cf6 100644
--- a/host/lib/usrp/usrp2/fw_common.h
+++ b/host/lib/usrp/usrp2/fw_common.h
@@ -34,7 +34,7 @@ extern "C" {
//defines the protocol version in this shared header
//increment this value when the protocol is changed
-#define USRP2_PROTO_VERSION 2
+#define USRP2_PROTO_VERSION 3
//used to differentiate control packets over data port
#define USRP2_INVALID_VRT_HEADER 0
@@ -70,9 +70,6 @@ typedef enum{
USRP2_CTRL_ID_WRITE_THESE_I2C_VALUES_BRO = 'h',
USRP2_CTRL_ID_COOL_IM_DONE_I2C_WRITE_DUDE = 'H',
- USRP2_CTRL_ID_SEND_STREAM_COMMAND_FOR_ME_BRO = '{',
- USRP2_CTRL_ID_GOT_THAT_STREAM_COMMAND_DUDE = '}',
-
USRP2_CTRL_ID_POKE_THIS_REGISTER_FOR_ME_BRO = 'p',
USRP2_CTRL_ID_OMG_POKED_REGISTER_SO_BAD_DUDE = 'P',
@@ -114,15 +111,6 @@ typedef struct{
_SINS_ uint8_t data[sizeof(_SINS_ uint32_t)];
} i2c_args;
struct {
- _SINS_ uint8_t now; //stream now?
- _SINS_ uint8_t continuous; //auto-reload commmands?
- _SINS_ uint8_t chain;
- _SINS_ uint8_t _pad[1];
- _SINS_ uint32_t secs;
- _SINS_ uint32_t ticks;
- _SINS_ uint32_t num_samps;
- } stream_cmd;
- struct {
_SINS_ uint32_t addr;
_SINS_ uint32_t data;
_SINS_ uint8_t num_bytes; //1, 2, 4
diff --git a/host/lib/usrp/usrp2/io_impl.cpp b/host/lib/usrp/usrp2/io_impl.cpp
index 367a1d9fb..a2e99c824 100644
--- a/host/lib/usrp/usrp2/io_impl.cpp
+++ b/host/lib/usrp/usrp2/io_impl.cpp
@@ -16,6 +16,7 @@
//
#include "usrp2_impl.hpp"
+#include "usrp2_regs.hpp"
#include <uhd/transport/convert_types.hpp>
#include <boost/format.hpp>
#include <boost/asio.hpp> //htonl and ntohl
@@ -39,14 +40,23 @@ void usrp2_impl::io_init(void){
_rx_copy_buff = asio::buffer("", 0);
//send a small data packet so the usrp2 knows the udp source port
- //and the maximum number of lines (32 bit words) per packet
managed_send_buffer::sptr send_buff = _data_transport->get_send_buff();
- boost::uint32_t data[2] = {
- htonl(USRP2_INVALID_VRT_HEADER),
- htonl(_max_rx_samples_per_packet)
- };
- memcpy(send_buff->cast<void*>(), data, sizeof(data));
+ boost::uint32_t data = htonl(USRP2_INVALID_VRT_HEADER);
+ memcpy(send_buff->cast<void*>(), &data, sizeof(data));
send_buff->done(sizeof(data));
+
+ //setup RX DSP regs
+ _iface->poke32(FR_RX_CTRL_NSAMPS_PER_PKT, _max_rx_samples_per_packet);
+ _iface->poke32(FR_RX_CTRL_NCHANNELS, 1);
+ _iface->poke32(FR_RX_CTRL_CLEAR_OVERRUN, 1); //reset
+ _iface->poke32(FR_RX_CTRL_VRT_HEADER, 0
+ | (0x1 << 28) //if data with stream id
+ | (0x1 << 26) //has trailer
+ | (0x3 << 22) //integer time other
+ | (0x1 << 20) //fractional time sample count
+ );
+ _iface->poke32(FR_RX_CTRL_VRT_STREAM_ID, 0);
+ _iface->poke32(FR_RX_CTRL_VRT_TRAILER, 0);
}
/***********************************************************************
diff --git a/host/lib/usrp/usrp2/mboard_impl.cpp b/host/lib/usrp/usrp2/mboard_impl.cpp
index 36bef4f25..48aeb2a62 100644
--- a/host/lib/usrp/usrp2/mboard_impl.cpp
+++ b/host/lib/usrp/usrp2/mboard_impl.cpp
@@ -119,40 +119,31 @@ void usrp2_impl::set_time_spec(const time_spec_t &time_spec, bool now){
}
void usrp2_impl::issue_ddc_stream_cmd(const stream_cmd_t &stream_cmd){
- //setup the out data
- usrp2_ctrl_data_t out_data;
- out_data.id = htonl(USRP2_CTRL_ID_SEND_STREAM_COMMAND_FOR_ME_BRO);
- out_data.data.stream_cmd.now = (stream_cmd.stream_now)? 1 : 0;
- out_data.data.stream_cmd.secs = htonl(stream_cmd.time_spec.secs);
- out_data.data.stream_cmd.ticks = htonl(stream_cmd.time_spec.get_ticks(get_master_clock_freq()));
-
- //set these to defaults, then change in the switch statement
- out_data.data.stream_cmd.continuous = 0;
- out_data.data.stream_cmd.chain = 0;
- out_data.data.stream_cmd.num_samps = htonl(stream_cmd.num_samps);
-
- //setup chain, num samps, and continuous below
- switch(stream_cmd.stream_mode){
- case stream_cmd_t::STREAM_MODE_START_CONTINUOUS:
- out_data.data.stream_cmd.continuous = 1;
- break;
-
- case stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS:
- out_data.data.stream_cmd.num_samps = htonl(0);
- break;
-
- case stream_cmd_t::STREAM_MODE_NUM_SAMPS_AND_DONE:
- //all set by defaults above
- break;
-
- case stream_cmd_t::STREAM_MODE_NUM_SAMPS_AND_MORE:
- out_data.data.stream_cmd.chain = 1;
- break;
- }
-
- //send and recv
- usrp2_ctrl_data_t in_data = _iface->ctrl_send_and_recv(out_data);
- UHD_ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_GOT_THAT_STREAM_COMMAND_DUDE);
+ UHD_ASSERT_THROW(stream_cmd.num_samps <= FR_RX_CTRL_MAX_SAMPS_PER_CMD);
+
+ //setup the mode to instruction flags
+ typedef boost::tuple<bool, bool, bool> inst_t;
+ static const uhd::dict<stream_cmd_t::stream_mode_t, inst_t> mode_to_inst = boost::assign::map_list_of
+ //reload, chain, samps
+ (stream_cmd_t::STREAM_MODE_START_CONTINUOUS, inst_t(true, true, false))
+ (stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS, inst_t(false, false, false))
+ (stream_cmd_t::STREAM_MODE_NUM_SAMPS_AND_DONE, inst_t(false, false, true))
+ (stream_cmd_t::STREAM_MODE_NUM_SAMPS_AND_MORE, inst_t(false, true, true))
+ ;
+
+ //setup the instruction flag values
+ bool inst_reload, inst_chain, inst_samps;
+ boost::tie(inst_reload, inst_chain, inst_samps) = mode_to_inst[stream_cmd.stream_mode];
+
+ //issue the stream command
+ _iface->poke32(FR_RX_CTRL_STREAM_CMD, FR_RX_CTRL_MAKE_CMD(
+ (inst_samps)? stream_cmd.num_samps : ((inst_chain)? _max_rx_samples_per_packet : 1),
+ (stream_cmd.stream_now)? 1 : 0,
+ (inst_chain)? 1 : 0,
+ (inst_reload)? 1 : 0
+ ));
+ _iface->poke32(FR_RX_CTRL_TIME_SECS, stream_cmd.time_spec.secs);
+ _iface->poke32(FR_RX_CTRL_TIME_TICKS, stream_cmd.time_spec.get_ticks(get_master_clock_freq()));
}
/***********************************************************************
diff --git a/host/lib/usrp/usrp2/usrp2_regs.hpp b/host/lib/usrp/usrp2/usrp2_regs.hpp
index 0e2a18756..67a342217 100644
--- a/host/lib/usrp/usrp2/usrp2_regs.hpp
+++ b/host/lib/usrp/usrp2/usrp2_regs.hpp
@@ -207,4 +207,25 @@
#define FR_ATR_FULL_TXSIDE FR_ATR_BASE + 12
#define FR_ATR_FULL_RXSIDE FR_ATR_BASE + 14
+///////////////////////////////////////////////////
+// ATR Controller, Slave 11
+///////////////////////////////////////////////////
+// The following 3 are logically a single command register.
+// They are clocked into the underlying fifo when time_ticks is written.
+#define FR_RX_CTRL_STREAM_CMD _SR_ADDR(SR_RX_CTRL + 0) // {now, chain, num_samples(30)
+#define FR_RX_CTRL_TIME_SECS _SR_ADDR(SR_RX_CTRL + 1)
+#define FR_RX_CTRL_TIME_TICKS _SR_ADDR(SR_RX_CTRL + 2)
+
+#define FR_RX_CTRL_CLEAR_OVERRUN _SR_ADDR(SR_RX_CTRL + 3) // write anything to clear overrun
+#define FR_RX_CTRL_VRT_HEADER _SR_ADDR(SR_RX_CTRL + 4) // word 0 of packet. FPGA fills in packet counter
+#define FR_RX_CTRL_VRT_STREAM_ID _SR_ADDR(SR_RX_CTRL + 5) // word 1 of packet.
+#define FR_RX_CTRL_VRT_TRAILER _SR_ADDR(SR_RX_CTRL + 6)
+#define FR_RX_CTRL_NSAMPS_PER_PKT _SR_ADDR(SR_RX_CTRL + 7)
+#define FR_RX_CTRL_NCHANNELS _SR_ADDR(SR_RX_CTRL + 8) // 1 in basic case, up to 4 for vector sources
+
+//helpful macros for dealing with stream cmd
+#define FR_RX_CTRL_MAX_SAMPS_PER_CMD 0x1fffffff
+#define FR_RX_CTRL_MAKE_CMD(nsamples, now, chain, reload) \
+ ((((now) & 0x1) << 31) | (((chain) & 0x1) << 30) | (((reload) & 0x1) << 29) | ((nsamples) & 0x1fffffff))
+
#endif /* INCLUDED_USRP2_REGS_HPP */