aboutsummaryrefslogtreecommitdiffstats
path: root/fpga/usrp2/vrt
diff options
context:
space:
mode:
Diffstat (limited to 'fpga/usrp2/vrt')
-rw-r--r--fpga/usrp2/vrt/.gitignore4
-rw-r--r--fpga/usrp2/vrt/Makefile.srcs20
-rw-r--r--fpga/usrp2/vrt/gen_context_pkt.v106
-rw-r--r--fpga/usrp2/vrt/trigger_context_pkt.v69
-rw-r--r--fpga/usrp2/vrt/vita_pkt_gen.v59
-rwxr-xr-xfpga/usrp2/vrt/vita_rx.build1
-rw-r--r--fpga/usrp2/vrt/vita_rx_chain.v114
-rw-r--r--fpga/usrp2/vrt/vita_rx_control.v231
-rw-r--r--fpga/usrp2/vrt/vita_rx_engine_glue.v95
-rw-r--r--fpga/usrp2/vrt/vita_rx_framer.v224
-rw-r--r--fpga/usrp2/vrt/vita_rx_tb.v246
-rwxr-xr-xfpga/usrp2/vrt/vita_tx.build1
-rw-r--r--fpga/usrp2/vrt/vita_tx_chain.v162
-rw-r--r--fpga/usrp2/vrt/vita_tx_control.v238
-rw-r--r--fpga/usrp2/vrt/vita_tx_deframer.v261
-rw-r--r--fpga/usrp2/vrt/vita_tx_engine_glue.v99
-rw-r--r--fpga/usrp2/vrt/vita_tx_tb.v193
17 files changed, 2123 insertions, 0 deletions
diff --git a/fpga/usrp2/vrt/.gitignore b/fpga/usrp2/vrt/.gitignore
new file mode 100644
index 000000000..446b2daae
--- /dev/null
+++ b/fpga/usrp2/vrt/.gitignore
@@ -0,0 +1,4 @@
+vita_rx_tb
+vita_tx_tb
+*.vcd
+*.sav
diff --git a/fpga/usrp2/vrt/Makefile.srcs b/fpga/usrp2/vrt/Makefile.srcs
new file mode 100644
index 000000000..84ba5dc29
--- /dev/null
+++ b/fpga/usrp2/vrt/Makefile.srcs
@@ -0,0 +1,20 @@
+#
+# Copyright 2010 Ettus Research LLC
+#
+
+##################################################
+# VRT Sources
+##################################################
+VRT_SRCS = $(abspath $(addprefix $(BASE_DIR)/../vrt/, \
+vita_rx_control.v \
+vita_rx_framer.v \
+vita_rx_chain.v \
+vita_tx_control.v \
+vita_tx_deframer.v \
+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
new file mode 100644
index 000000000..d6674e887
--- /dev/null
+++ b/fpga/usrp2/vrt/gen_context_pkt.v
@@ -0,0 +1,106 @@
+//
+// 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 gen_context_pkt
+ #(parameter PROT_ENG_FLAGS=1,
+ parameter DSP_NUMBER=0)
+ (input clk, input reset, input clear,
+ input trigger, output sent,
+ input [31:0] streamid,
+ input [63:0] vita_time,
+ input [31:0] message,
+ input [31:0] seqnum,
+ output [35:0] data_o, output src_rdy_o, input dst_rdy_i);
+
+ localparam CTXT_IDLE = 0;
+ localparam CTXT_PROT_ENG = 1;
+ localparam CTXT_HEADER = 2;
+ localparam CTXT_STREAMID = 3;
+ localparam CTXT_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;
+ reg [3:0] seqno;
+ reg [3:0] ctxt_state;
+ reg [63:0] err_time;
+ reg [31:0] stored_message;
+
+ always @(posedge clk)
+ if(reset | clear)
+ stored_message <= 0;
+ else
+ if(trigger)
+ stored_message <= message;
+ else if(ctxt_state == CTXT_DONE)
+ stored_message <= 0;
+
+ // Don't want to clear most of this to avoid getting stuck with a half packet in the pipe
+ always @(posedge clk)
+ if(reset)
+ begin
+ ctxt_state <= CTXT_IDLE;
+ seqno <= 0;
+ end
+ else
+ case(ctxt_state)
+ CTXT_IDLE :
+ if(trigger)
+ begin
+ err_time <= vita_time;
+ if(PROT_ENG_FLAGS)
+ ctxt_state <= CTXT_PROT_ENG;
+ else
+ ctxt_state <= CTXT_HEADER;
+ end
+
+ CTXT_DONE :
+ begin
+ ctxt_state <= CTXT_IDLE;
+ seqno <= seqno + 4'd1;
+ end
+ default :
+ if(dst_rdy_int)
+ ctxt_state <= ctxt_state + 1;
+ endcase // case (ctxt_state)
+
+ assign src_rdy_int = ~( (ctxt_state == CTXT_IDLE) | (ctxt_state == CTXT_DONE) );
+
+ always @*
+ case(ctxt_state)
+ CTXT_PROT_ENG : data_int <= { 2'b01, 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_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 };
+ default : data_int <= {2'b00, 32'b00};
+ endcase // case (ctxt_state)
+
+ fifo_short #(.WIDTH(34)) ctxt_fifo
+ (.clk(clk), .reset(reset), .clear(0),
+ .datain(data_int), .src_rdy_i(src_rdy_int), .dst_rdy_o(dst_rdy_int),
+ .dataout(data_o[33:0]), .src_rdy_o(src_rdy_o), .dst_rdy_i(dst_rdy_i));
+ assign data_o[35:34] = 2'b00;
+
+endmodule // gen_context_pkt
diff --git a/fpga/usrp2/vrt/trigger_context_pkt.v b/fpga/usrp2/vrt/trigger_context_pkt.v
new file mode 100644
index 000000000..3d9c2e5c6
--- /dev/null
+++ b/fpga/usrp2/vrt/trigger_context_pkt.v
@@ -0,0 +1,69 @@
+//
+// 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 trigger_context_pkt
+ #(parameter BASE=0)
+ (input clk, input reset, input clear,
+ input set_stb, input [7:0] set_addr, input [31:0] set_data,
+ input packet_consumed, output reg trigger);
+
+ wire [23:0] cycles;
+ wire [15:0] packets;
+ wire [6:0] dummy1;
+ wire [14:0] dummy2;
+ wire enable_cycle, enable_consumed;
+ reg [30:0] cycle_count, packet_count;
+
+
+ setting_reg #(.my_addr(BASE+4), .at_reset(0)) sr_cycles
+ (.clk(clk),.rst(reset),.strobe(set_stb),.addr(set_addr),
+ .in(set_data),.out({enable_cycle,dummy1,cycles}),.changed());
+
+ setting_reg #(.my_addr(BASE+5), .at_reset(0)) sr_packets
+ (.clk(clk),.rst(reset),.strobe(set_stb),.addr(set_addr),
+ .in(set_data),.out({enable_consumed,dummy2,packets}),.changed());
+
+ always @(posedge clk)
+ if(reset | clear)
+ cycle_count <= 0;
+ else
+ if(trigger)
+ cycle_count <= 0;
+ else if(enable_cycle)
+ cycle_count <= cycle_count + 1;
+
+ always @(posedge clk)
+ if(reset | clear)
+ packet_count <= 0;
+ else
+ if(trigger)
+ packet_count <= 0;
+ else if(packet_consumed & enable_consumed)
+ packet_count <= packet_count + 1;
+
+ always @(posedge clk)
+ if(reset | clear)
+ trigger <= 0;
+ else
+ if((cycle_count > cycles)|(packet_count > packets))
+ trigger <= 1;
+ else
+ trigger <= 0;
+
+endmodule // trigger_context_pkt
diff --git a/fpga/usrp2/vrt/vita_pkt_gen.v b/fpga/usrp2/vrt/vita_pkt_gen.v
new file mode 100644
index 000000000..b962254a6
--- /dev/null
+++ b/fpga/usrp2/vrt/vita_pkt_gen.v
@@ -0,0 +1,59 @@
+//
+// 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 vita_pkt_gen
+ (input clk, input reset, input clear,
+ input [15:0] len,
+ output [35:0] data_o, output src_rdy_o, input dst_rdy_i);
+
+ reg [15:0] state;
+ reg [31:0] seq, data;
+
+ wire sof = (state == 0);
+ wire eof = (state == (len-1));
+ wire consume = src_rdy_o & dst_rdy_i;
+
+ assign src_rdy_o = 1;
+
+ always @(posedge clk)
+ if(reset | clear)
+ begin
+ state <= 0;
+ seq <= 0;
+ end
+ else
+ if(consume)
+ if(eof)
+ begin
+ state <= 0;
+ seq <= seq + 1;
+ end
+ else
+ state <= state + 1;
+
+ always @*
+ case(state)
+ 0 : data <= {24'h000,seq[3:0],len};
+ 1 : data <= seq;
+ default : data <= {~state,state};
+ endcase // case (state)
+
+ assign data_o = {2'b00, eof, sof, data};
+
+endmodule // vita_pkt_gen
diff --git a/fpga/usrp2/vrt/vita_rx.build b/fpga/usrp2/vrt/vita_rx.build
new file mode 100755
index 000000000..010d1be6e
--- /dev/null
+++ b/fpga/usrp2/vrt/vita_rx.build
@@ -0,0 +1 @@
+iverilog -Wimplict -Wportbind -y ../models -y . -y ../control_lib/ -y ../fifo -y ../coregen -y /opt/Xilinx/10.1/ISE/verilog/src/XilinxCoreLib -y /opt/Xilinx/10.1/ISE/verilog/src/unisims/ -y ../timing -o vita_rx_tb vita_rx_tb.v
diff --git a/fpga/usrp2/vrt/vita_rx_chain.v b/fpga/usrp2/vrt/vita_rx_chain.v
new file mode 100644
index 000000000..2788dc9d5
--- /dev/null
+++ b/fpga/usrp2/vrt/vita_rx_chain.v
@@ -0,0 +1,114 @@
+//
+// 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/>.
+//
+
+
+module vita_rx_chain
+ #(parameter BASE=0,
+ parameter UNIT=0,
+ parameter FIFOSIZE=10,
+ 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 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;
+ wire clear_int;
+ setting_reg #(.my_addr(BASE+8)) sr
+ (.clk(clk),.rst(reset),.strobe(set_stb),.addr(set_addr),
+ .in(set_data),.out(),.changed(clear_int));
+
+ 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),
+ .vita_time(vita_time), .overrun(overrun),
+ .sample(sample), .run(run), .strobe(strobe),
+ .sample_fifo_o(sample_data), .sample_fifo_dst_rdy_i(sample_dst_rdy), .sample_fifo_src_rdy_o(sample_src_rdy),
+ .debug_rx(vrc_debug));
+
+ vita_rx_framer #(.BASE(BASE), .MAXCHAN(1)) vita_rx_framer
+ (.clk(clk), .reset(reset), .clear(clear),
+ .set_stb(set_stb),.set_addr(set_addr),.set_data(set_data),
+ .sample_fifo_i(sample_data), .sample_fifo_dst_rdy_o(sample_dst_rdy), .sample_fifo_src_rdy_i(sample_src_rdy),
+ .data_o(rx_data_int), .src_rdy_o(rx_src_rdy_int), .dst_rdy_i(rx_dst_rdy_int),
+ .debug_rx(vrf_debug) );
+
+ 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] rx_data_int2;
+ wire rx_src_rdy_int2, rx_dst_rdy_int2;
+
+ 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(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));
+
+ 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));
+
+ add_routing_header #(.PORT_SEL(UNIT),
+ .PROT_ENG_FLAGS(PROT_ENG_FLAGS)) dsp_routing_header
+ (.clk(clk), .reset(reset), .clear(clear),
+ .data_i(rx_data_int2), .src_rdy_i(rx_src_rdy_int2), .dst_rdy_o(rx_dst_rdy_int2),
+ .data_o(rx_data_o), .src_rdy_o(rx_src_rdy_o), .dst_rdy_i(rx_dst_rdy_i) );
+
+ //only clear once a full packet has passed through the output interface
+ reg xfer_pkt, clear_oneshot;
+ assign clear = (clear_oneshot)? ~xfer_pkt : 0;
+ always @(posedge clk) begin
+
+ if (reset || clear) begin
+ clear_oneshot <= 0;
+ end
+ else if (clear_int) begin
+ clear_oneshot <= 1;
+ end
+
+ if (reset || clear) begin
+ xfer_pkt <= 0;
+ end
+ else if (rx_src_rdy_o && rx_dst_rdy_i) begin
+ xfer_pkt <= ~rx_data_o[33];
+ end
+ end
+
+ assign debug = vrc_debug; // | vrf_debug;
+
+endmodule // vita_rx_chain
diff --git a/fpga/usrp2/vrt/vita_rx_control.v b/fpga/usrp2/vrt/vita_rx_control.v
new file mode 100644
index 000000000..daec734a8
--- /dev/null
+++ b/fpga/usrp2/vrt/vita_rx_control.v
@@ -0,0 +1,231 @@
+//
+// 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 vita_rx_control
+ #(parameter BASE=0,
+ parameter WIDTH=32)
+ (input clk, input reset, input clear,
+ input set_stb, input [7:0] set_addr, input [31:0] set_data,
+
+ input [63:0] vita_time,
+ output overrun,
+
+ // To vita_rx_framer
+ output [5+64+WIDTH-1:0] sample_fifo_o,
+ output sample_fifo_src_rdy_o,
+ input sample_fifo_dst_rdy_i,
+
+ // From DSP Core
+ input [WIDTH-1:0] sample,
+ output run,
+ input strobe,
+
+ output [31:0] debug_rx
+ );
+
+ // FIXME add TX Interruption (halt, pause, continue) functionality
+
+ wire [63:0] new_time;
+ wire [31:0] new_command;
+ wire sc_pre1;
+
+ wire [63:0] rcvtime_pre;
+ reg [63:0] rcvtime;
+ wire [27:0] numlines_pre;
+ wire send_imm_pre, chain_pre, reload_pre, stop_pre;
+ reg send_imm, chain, reload;
+ wire read_ctrl, not_empty_ctrl, write_ctrl;
+ reg sc_pre2;
+ wire [33:0] fifo_line;
+ reg [27:0] lines_left, lines_total;
+ reg [2:0] ibs_state;
+ wire now, early, late;
+ wire sample_fifo_in_rdy;
+
+ setting_reg #(.my_addr(BASE)) sr_cmd
+ (.clk(clk),.rst(reset),.strobe(set_stb),.addr(set_addr),
+ .in(set_data),.out(new_command),.changed());
+
+ setting_reg #(.my_addr(BASE+1)) sr_time_h
+ (.clk(clk),.rst(reset),.strobe(set_stb),.addr(set_addr),
+ .in(set_data),.out(new_time[63:32]),.changed());
+
+ setting_reg #(.my_addr(BASE+2)) sr_time_l
+ (.clk(clk),.rst(reset),.strobe(set_stb),.addr(set_addr),
+ .in(set_data),.out(new_time[31:0]),.changed(sc_pre1));
+
+ // FIFO to store commands sent from the settings bus
+ always @(posedge clk)
+ if(reset | clear)
+ sc_pre2 <= 0;
+ else
+ sc_pre2 <= sc_pre1;
+
+ assign write_ctrl = sc_pre1 & ~sc_pre2;
+
+ wire [4:0] command_queue_len;
+
+ fifo_short #(.WIDTH(96)) commandfifo
+ (.clk(clk),.reset(reset),.clear(clear),
+ .datain({new_command,new_time}), .src_rdy_i(write_ctrl), .dst_rdy_o(),
+ .dataout({send_imm_pre,chain_pre,reload_pre,stop_pre,numlines_pre,rcvtime_pre}),
+ .src_rdy_o(not_empty_ctrl), .dst_rdy_i(read_ctrl),
+ .occupied(command_queue_len), .space() );
+
+ reg [33:0] pkt_fifo_line;
+
+ localparam IBS_IDLE = 0;
+ localparam IBS_WAITING = 1;
+ localparam IBS_RUNNING = 2;
+ localparam IBS_OVERRUN = 4;
+ localparam IBS_BROKENCHAIN = 5;
+ localparam IBS_LATECMD = 6;
+ localparam IBS_ZEROLEN = 7;
+
+ wire signal_cmd_done = (lines_left == 1) & (~chain | (not_empty_ctrl & stop_pre));
+ wire signal_overrun = (ibs_state == IBS_OVERRUN);
+ wire signal_brokenchain = (ibs_state == IBS_BROKENCHAIN);
+ wire signal_latecmd = (ibs_state == IBS_LATECMD);
+ wire signal_zerolen = (ibs_state == IBS_ZEROLEN);
+
+ // Buffer of samples for while we're writing the packet headers
+ wire [4:0] flags = {signal_zerolen,signal_overrun,signal_brokenchain,signal_latecmd,signal_cmd_done};
+
+ wire attempt_sample_write = ((run & strobe) | (ibs_state==IBS_OVERRUN) |
+ (ibs_state==IBS_BROKENCHAIN) | (ibs_state==IBS_LATECMD) |
+ (ibs_state==IBS_ZEROLEN));
+
+ fifo_short #(.WIDTH(5+64+WIDTH)) rx_sample_fifo
+ (.clk(clk),.reset(reset),.clear(clear),
+ .datain({flags,vita_time,sample}), .src_rdy_i(attempt_sample_write), .dst_rdy_o(sample_fifo_in_rdy),
+ .dataout(sample_fifo_o),
+ .src_rdy_o(sample_fifo_src_rdy_o), .dst_rdy_i(sample_fifo_dst_rdy_i),
+ .space(), .occupied() );
+
+ // Inband Signalling State Machine
+ time_compare
+ time_compare (.time_now(vita_time), .trigger_time(rcvtime), .now(now), .early(early), .late(late));
+
+ wire go_now = now | send_imm;
+ wire full = ~sample_fifo_in_rdy;
+
+ reg too_late;
+
+ always @(posedge clk)
+ if(reset | clear)
+ too_late <= 0;
+ else
+ too_late <= late & ~send_imm;
+
+ reg late_valid;
+
+ always @(posedge clk)
+ if(reset | clear)
+ begin
+ ibs_state <= IBS_IDLE;
+ lines_left <= 0;
+ lines_total <= 0;
+ rcvtime <= 0;
+ send_imm <= 0;
+ chain <= 0;
+ reload <= 0;
+ late_valid <= 0;
+ end
+ else
+ case(ibs_state)
+ IBS_IDLE :
+ if(not_empty_ctrl)
+ begin
+ lines_left <= numlines_pre;
+ lines_total <= numlines_pre;
+ rcvtime <= rcvtime_pre;
+ late_valid <= 0;
+ if(stop_pre)
+ ibs_state <= IBS_ZEROLEN;
+ else
+ ibs_state <= IBS_WAITING;
+ send_imm <= send_imm_pre;
+ chain <= chain_pre;
+ reload <= reload_pre;
+ end
+ IBS_WAITING :
+ begin
+ late_valid <= 1;
+ if(late_valid)
+ if(go_now)
+ ibs_state <= IBS_RUNNING;
+ else if(too_late)
+ ibs_state <= IBS_LATECMD;
+ end
+ IBS_RUNNING :
+ if(strobe)
+ if(full)
+ ibs_state <= IBS_OVERRUN;
+ else
+ begin
+ lines_left <= lines_left - 1;
+ if(lines_left == 1)
+ if(~chain)
+ ibs_state <= IBS_IDLE;
+ else if(~not_empty_ctrl & reload)
+ begin
+ ibs_state <= IBS_RUNNING;
+ lines_left <= lines_total;
+ end
+ else if(~not_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(stop_pre) // If we are told to stop here
+ ibs_state <= IBS_IDLE;
+ else
+ ibs_state <= IBS_RUNNING;
+ end
+ end // else: !if(full)
+ IBS_OVERRUN :
+ if(sample_fifo_in_rdy)
+ ibs_state <= IBS_IDLE;
+ IBS_LATECMD :
+ if(sample_fifo_in_rdy)
+ ibs_state <= IBS_IDLE;
+ IBS_BROKENCHAIN :
+ if(sample_fifo_in_rdy)
+ ibs_state <= IBS_IDLE;
+ IBS_ZEROLEN :
+ if(sample_fifo_in_rdy)
+ ibs_state <= IBS_IDLE;
+ endcase // case(ibs_state)
+
+ assign overrun = (ibs_state == IBS_OVERRUN);
+ assign run = (ibs_state == IBS_RUNNING);
+
+ assign read_ctrl = ( (ibs_state == IBS_IDLE) | ((ibs_state == IBS_RUNNING) & strobe & ~full & (lines_left==1) & chain) )
+ & not_empty_ctrl;
+
+ assign debug_rx = { { ibs_state[2:0], command_queue_len },
+ { 8'd0 },
+ { go_now, too_late, run, strobe, read_ctrl, write_ctrl, 1'b0, ~not_empty_ctrl },
+ { 2'b0, overrun, chain_pre, sample_fifo_in_rdy, attempt_sample_write, sample_fifo_src_rdy_o,sample_fifo_dst_rdy_i} };
+
+endmodule // vita_rx_control
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
new file mode 100644
index 000000000..6e4b8025d
--- /dev/null
+++ b/fpga/usrp2/vrt/vita_rx_framer.v
@@ -0,0 +1,224 @@
+//
+// 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/>.
+//
+
+
+module vita_rx_framer
+ #(parameter BASE=0,
+ parameter MAXCHAN=1)
+ (input clk, input reset, input clear,
+ input set_stb, input [7:0] set_addr, input [31:0] set_data,
+
+ // To FIFO interface of Buffer Pool
+ output [35:0] data_o,
+ input dst_rdy_i,
+ output src_rdy_o,
+
+ // From vita_rx_control
+ input [5+64+(32*MAXCHAN)-1:0] sample_fifo_i,
+ input sample_fifo_src_rdy_i,
+ output sample_fifo_dst_rdy_o,
+
+ output [31:0] debug_rx
+ );
+
+ localparam SAMP_WIDTH = 5+64+(32*MAXCHAN);
+ reg [3:0] sample_phase;
+ wire [3:0] numchan;
+ wire [4:0] flags_fifo_o = sample_fifo_i[SAMP_WIDTH-1:SAMP_WIDTH-5];
+ wire [63:0] vita_time_fifo_o = sample_fifo_i[SAMP_WIDTH-6:SAMP_WIDTH-69];
+
+ reg [31:0] data_fifo_o;
+
+ // The tools won't synthesize properly without this kludge because of the variable
+ // parameter length
+
+ wire [127:0] FIXED_WIDTH_KLUDGE = sample_fifo_i;
+ always @*
+ case(sample_phase)
+ 4'd0 : data_fifo_o = FIXED_WIDTH_KLUDGE[31:0];
+ 4'd1 : data_fifo_o = FIXED_WIDTH_KLUDGE[63:32];
+ 4'd2 : data_fifo_o = FIXED_WIDTH_KLUDGE[95:64];
+ 4'd3 : data_fifo_o = FIXED_WIDTH_KLUDGE[127:96];
+ default : data_fifo_o = 32'hDEADBEEF;
+ endcase // case (sample_phase)
+
+ wire clear_pkt_count, pkt_fifo_rdy, sample_fifo_in_rdy;
+
+ wire [31:0] vita_header, vita_streamid, vita_trailer;
+ wire [15:0] samples_per_packet;
+
+ reg [33:0] pkt_fifo_line;
+ reg [3:0] vita_state;
+ reg [15:0] sample_ctr;
+ reg [3:0] pkt_count;
+
+ wire [15:0] vita_pkt_len = samples_per_packet + 6;
+ //wire [4:0] flags = {signal_zerolen,signal_overrun,signal_brokenchain,signal_latecmd,signal_cmd_done};
+
+ setting_reg #(.my_addr(BASE+4)) sr_header
+ (.clk(clk),.rst(reset),.strobe(set_stb),.addr(set_addr),
+ .in(set_data),.out(vita_header),.changed());
+
+ setting_reg #(.my_addr(BASE+5)) sr_streamid
+ (.clk(clk),.rst(reset),.strobe(set_stb),.addr(set_addr),
+ .in(set_data),.out(vita_streamid),.changed(clear_pkt_count));
+
+ setting_reg #(.my_addr(BASE+6)) sr_trailer
+ (.clk(clk),.rst(reset),.strobe(set_stb),.addr(set_addr),
+ .in(set_data),.out(vita_trailer),.changed());
+
+ setting_reg #(.my_addr(BASE+7),.width(16)) sr_samples_per_pkt
+ (.clk(clk),.rst(reset),.strobe(set_stb),.addr(set_addr),
+ .in(set_data),.out(samples_per_packet),.changed());
+
+ assign numchan = 0;/*
+ setting_reg #(.my_addr(BASE+8),.width(4), .at_reset(0)) sr_numchan
+ (.clk(clk),.rst(reset),.strobe(set_stb),.addr(set_addr),
+ .in(set_data),.out(numchan),.changed());
+ */
+
+ // Output FIFO for packetized data
+ localparam VITA_IDLE = 0;
+ localparam VITA_HEADER = 1;
+ localparam VITA_STREAMID = 2;
+ 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)
+ pkt_count <= 0;
+ else if((vita_state == VITA_TRAILER) & pkt_fifo_rdy)
+ pkt_count <= pkt_count + 1;
+
+ wire has_streamid = vita_header[28];
+ wire has_trailer = vita_header[26];
+ reg trl_eob;
+
+ always @*
+ case(vita_state)
+ // Data packets are IF Data packets with or w/o streamid, no classid, with trailer
+ VITA_HEADER : pkt_fifo_line <= {2'b01,3'b000,vita_header[28],2'b01,vita_header[25:24],
+ vita_header[23:20],pkt_count[3:0],vita_pkt_len[15:0]};
+ VITA_STREAMID : pkt_fifo_line <= {2'b00,vita_streamid};
+ 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'd5};
+ VITA_ERR_STREAMID : pkt_fifo_line <= {2'b00,vita_streamid};
+ 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};
+
+ default : pkt_fifo_line <= 34'h0_FFFF_FFFF;
+ endcase // case (vita_state)
+
+ always @(posedge clk)
+ if(reset | clear)
+ begin
+ vita_state <= VITA_IDLE;
+ sample_ctr <= 0;
+ sample_phase <= 0;
+ end
+ else
+ if(vita_state==VITA_IDLE)
+ begin
+ sample_ctr <= 1;
+ sample_phase <= 0;
+ if(sample_fifo_src_rdy_i)
+ if(|flags_fifo_o[4:1])
+ vita_state <= VITA_ERR_HEADER;
+ else
+ vita_state <= VITA_HEADER;
+ end
+ else if(pkt_fifo_rdy)
+ case(vita_state)
+ VITA_HEADER :
+ if(has_streamid)
+ vita_state <= VITA_STREAMID;
+ else
+ vita_state <= VITA_TICS;
+ VITA_PAYLOAD :
+ if(sample_fifo_src_rdy_i)
+ begin
+ if(sample_phase == numchan)
+ begin
+ sample_phase <= 0;
+ sample_ctr <= sample_ctr + 1;
+ trl_eob <= flags_fifo_o[0];
+ if(sample_ctr == samples_per_packet)
+ vita_state <= VITA_TRAILER;
+ if(|flags_fifo_o) // end early if any flag is set
+ vita_state <= VITA_TRAILER;
+ end
+ else
+ sample_phase <= sample_phase + 1;
+ end // if (sample_fifo_src_rdy_i)
+ VITA_ERR_PAYLOAD :
+ vita_state <= VITA_IDLE;
+ VITA_TRAILER :
+ vita_state <= VITA_IDLE;
+ default :
+ vita_state <= vita_state + 1;
+ endcase // case (vita_state)
+
+ reg req_write_pkt_fifo;
+ always @*
+ case(vita_state)
+ VITA_IDLE :
+ req_write_pkt_fifo <= 0;
+ 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_TICS, VITA_ERR_TICS2, VITA_ERR_PAYLOAD :
+ req_write_pkt_fifo <= 1;
+ default :
+ req_write_pkt_fifo <= 0;
+ endcase // case (vita_state)
+
+ //wire req_write_pkt_fifo = (vita_state != VITA_IDLE) & (sample_fifo_src_rdy_i | (vita_state != VITA_PAYLOAD));
+
+ // Short FIFO to buffer between us and the FIFOs outside
+ fifo_short #(.WIDTH(34)) rx_pkt_fifo
+ (.clk(clk), .reset(reset), .clear(clear),
+ .datain(pkt_fifo_line), .src_rdy_i(req_write_pkt_fifo), .dst_rdy_o(pkt_fifo_rdy),
+ .dataout(data_o[33:0]), .src_rdy_o(src_rdy_o), .dst_rdy_i(dst_rdy_i),
+ .space(),.occupied() );
+
+ assign data_o[35:34] = 2'b00; // Always write full lines
+ assign sample_fifo_dst_rdy_o = pkt_fifo_rdy &
+ ( ((vita_state==VITA_PAYLOAD) &
+ (sample_phase == numchan) &
+ ~|flags_fifo_o[4:1]) |
+ (vita_state==VITA_ERR_PAYLOAD));
+
+ assign debug_rx = vita_state;
+
+endmodule // vita_rx_framer
diff --git a/fpga/usrp2/vrt/vita_rx_tb.v b/fpga/usrp2/vrt/vita_rx_tb.v
new file mode 100644
index 000000000..8cd08a972
--- /dev/null
+++ b/fpga/usrp2/vrt/vita_rx_tb.v
@@ -0,0 +1,246 @@
+//
+// 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 vita_rx_tb;
+
+ localparam DECIM = 8'd4;
+ localparam MAXCHAN=1;
+ localparam NUMCHAN=1;
+
+ reg clk = 0;
+ reg reset = 1;
+
+ initial #1000 reset = 0;
+ always #50 clk = ~clk;
+
+ initial $dumpfile("vita_rx_tb.vcd");
+ initial $dumpvars(0,vita_rx_tb);
+
+ wire [(MAXCHAN*32)-1:0] sample;
+ wire strobe, run;
+ wire [35:0] data_o;
+ wire src_rdy;
+ reg dst_rdy = 1;
+ wire [63:0] vita_time;
+
+ reg set_stb = 0;
+ reg [7:0] set_addr;
+ reg [31:0] set_data;
+ wire set_stb_dsp;
+ wire [7:0] set_addr_dsp;
+ wire [31:0] set_data_dsp;
+
+ /*
+ settings_bus_crossclock settings_bus_xclk_dsp
+ (.clk_i(clk), .rst_i(reset), .set_stb_i(set_stb), .set_addr_i(set_addr), .set_data_i(set_data),
+ .clk_o(clk), .rst_o(reset), .set_stb_o(set_stb_dsp), .set_addr_o(set_addr_dsp), .set_data_o(set_data_dsp));
+ */
+
+ wire sample_dst_rdy, sample_src_rdy;
+ //wire [99:0] sample_data_o;
+ wire [64+5+(MAXCHAN*32)-1:0] sample_data_o;
+
+ vita_rx_control #(.BASE(0), .WIDTH(32*MAXCHAN)) vita_rx_control
+ (.clk(clk), .reset(reset), .clear(0),
+ .set_stb(set_stb), .set_addr(set_addr), .set_data(set_data),
+ .vita_time(vita_time), .overrun(overrun),
+ .sample_fifo_o(sample_data_o), .sample_fifo_dst_rdy_i(sample_dst_rdy), .sample_fifo_src_rdy_o(sample_src_rdy),
+ .sample(sample), .run(run), .strobe(strobe));
+
+ vita_rx_framer #(.BASE(0), .MAXCHAN(MAXCHAN)) vita_rx_framer
+ (.clk(clk), .reset(reset), .clear(0),
+ .set_stb(set_stb), .set_addr(set_addr), .set_data(set_data),
+ .data_o(data_o), .dst_rdy_i(dst_rdy), .src_rdy_o(src_rdy),
+ .sample_fifo_i(sample_data_o), .sample_fifo_dst_rdy_o(sample_dst_rdy), .sample_fifo_src_rdy_i(sample_src_rdy),
+ .fifo_occupied(), .fifo_full(), .fifo_empty() );
+
+ rx_dsp_model rx_dsp_model
+ (.clk(clk), .reset(reset), .run(run), .decim(DECIM), .strobe(strobe), .sample(sample[31:0]));
+
+ generate
+ if(MAXCHAN>1)
+ assign sample[(MAXCHAN*32)-1:32] = 0;
+ endgenerate
+
+ time_64bit #(.TICKS_PER_SEC(120000000), .BASE(0)) time_64bit
+ (.clk(clk), .rst(reset),
+ .set_stb(set_stb), .set_addr(set_addr), .set_data(set_data),
+ .pps(0), .vita_time(vita_time));
+
+ always @(posedge clk)
+ if(src_rdy & dst_rdy)
+ begin
+ if(data_o[32] & ~data_o[33])
+ begin
+ $display("RX-PKT-START %d",$time);
+ $display(" RX-PKT-DAT %x",data_o[31:0]);
+ end
+ else if(data_o[32] & data_o[33])
+ begin
+ $display(" RX-PKT-DAT %x -- With ERR",data_o[31:0]);
+ $display("RX-PKT-ERR %d",$time);
+ end
+ else if(~data_o[32] & data_o[33])
+ begin
+ $display(" RX-PKT-DAT %x",data_o[31:0]);
+ $display("RX-PKT-END %d",$time);
+ end
+ else
+ $display(" RX-PKT DAT %x",data_o[31:0]);
+ end
+
+ initial
+ begin
+ @(negedge reset);
+ @(posedge clk);
+ write_setting(4,32'h15F00000); // VITA header
+ write_setting(5,32'hF00D1234); // VITA streamid
+ write_setting(6,32'hE0000000); // VITA trailer
+ write_setting(7,8); // Samples per VITA packet
+ write_setting(8,NUMCHAN); // Vector length
+
+ queue_rx_cmd(1,1,0,10,32'h0,32'h0); // send imm, single packet
+ #10000;
+
+ queue_rx_cmd(1,0,0,0,32'h0,32'h0); // send imm, single packet
+ //queue_rx_cmd(1,1,0,0,32'h0,32'h0); // send imm, single packet
+
+ //queue_rx_cmd(1,0,0,0,32'h0,32'h0); // send imm, single packet
+
+ /*
+ queue_rx_cmd(1,0,0,8,32'h0,32'h0); // send imm, single packet
+ queue_rx_cmd(1,0,0,16,32'h0,32'h0); // send imm, 2 packets worth
+ queue_rx_cmd(1,0,0,7,32'h0,32'h0); // send imm, 1 short packet worth
+ queue_rx_cmd(1,0,0,9,32'h0,32'h0); // send imm, just longer than 1 packet
+
+ queue_rx_cmd(1,1,0,16,32'h0,32'h0); // chained
+ queue_rx_cmd(0,0,0,8,32'h0,32'h0); // 2nd in chain
+
+ queue_rx_cmd(1,1,0,17,32'h0,32'h0); // chained, odd length
+ queue_rx_cmd(0,0,0,9,32'h0,32'h0); // 2nd in chain, also odd length
+
+ queue_rx_cmd(0,0,0,8,32'h0,32'h340); // send at, on time
+ queue_rx_cmd(0,0,0,8,32'h0,32'h100); // send at, but late
+
+ #100000;
+ $display("\nChained, break chain\n");
+ queue_rx_cmd(1,1,0,8,32'h0,32'h0); // chained, but break chain
+ #100000;
+ $display("\nSingle packet\n");
+ queue_rx_cmd(1,0,0,8,32'h0,32'h0); // send imm, single packet
+ #100000;
+ $display("\nEnd chain with zero samples, shouldn't error\n");
+ queue_rx_cmd(1,1,0,8,32'h0,32'h0); // chained
+ queue_rx_cmd(0,0,0,0,32'h0,32'h0); // end chain with zero samples, should keep us out of error
+ #100000;
+
+ $display("\nEnd chain with zero samples on odd-length, shouldn't error\n");
+ queue_rx_cmd(1,1,0,14,32'h0,32'h0); // chained
+ queue_rx_cmd(0,0,0,0,32'h0,32'h0); // end chain with zero samples, should keep us out of error
+ #100000;
+ $display("Should have gotten 14 samples and EOF by now\n");
+
+ queue_rx_cmd(1,1,0,9,32'h0,32'h0); // chained, but break chain, odd length
+ #100000;
+ dst_rdy <= 0; // stop pulling out of fifo so we can get an overrun
+ queue_rx_cmd(1,0,0,100,32'h0,32'h0); // long enough to fill the fifos
+ queue_rx_cmd(1,0,0,5,32'h0,32'h0); // this command waits until the previous error packet is sent
+ #100000;
+ dst_rdy <= 1; // restart the reads so we can see what we got
+ #100000;
+ dst_rdy <= 0; // stop pulling out of fifo so we can get an overrun
+ queue_rx_cmd(1,1,0,100,32'h0,32'h0); // long enough to fill the fifos
+ //queue_rx_cmd(1,0,0,5,32'h0,32'h0); // this command waits until the previous error packet is sent
+ #100000;
+ @(posedge clk);
+ dst_rdy <= 1;
+ */
+ #100000 $finish;
+ end
+
+ task write_setting;
+ input [7:0] addr;
+ input [31:0] data;
+ begin
+ set_stb <= 0;
+ @(posedge clk);
+ set_addr <= addr;
+ set_data <= data;
+ set_stb <= 1;
+ @(posedge clk);
+ set_stb <= 0;
+ end
+ endtask // write_setting
+
+ task queue_rx_cmd;
+ input send_imm;
+ input chain;
+ input reload;
+ input [28:0] lines;
+ input [31:0] secs;
+ input [31:0] tics;
+ begin
+ write_setting(0,{send_imm,chain,reload,lines});
+ write_setting(1,secs);
+ write_setting(2,tics);
+ end
+ endtask // queue_rx_cmd
+
+endmodule // rx_control_tb
+
+module rx_dsp_model
+ (input clk, input reset,
+ input run,
+ input [7:0] decim,
+ output strobe,
+ output [31:0] sample);
+
+ reg [15:0] pktnum = 0;
+ reg [15:0] counter = 0;
+
+ reg run_d1;
+ always @(posedge clk) run_d1 <= run;
+
+ always @(posedge clk)
+ if(run & ~run_d1)
+ begin
+ counter <= 0;
+ pktnum <= pktnum + 1;
+ end
+ else if(run & strobe)
+ counter <= counter + 1;
+
+ assign sample = {pktnum,counter};
+
+ reg [7:0] stb_ctr = 0;
+
+ always @(posedge clk)
+ if(reset)
+ stb_ctr <= 0;
+ else if(run & ~run_d1)
+ stb_ctr <= 1;
+ else if(run)
+ if(stb_ctr == decim-1)
+ stb_ctr <= 0;
+ else
+ stb_ctr <= stb_ctr + 1;
+
+ assign strobe = stb_ctr == decim-1;
+
+endmodule // rx_dsp_model
diff --git a/fpga/usrp2/vrt/vita_tx.build b/fpga/usrp2/vrt/vita_tx.build
new file mode 100755
index 000000000..e7106aa10
--- /dev/null
+++ b/fpga/usrp2/vrt/vita_tx.build
@@ -0,0 +1 @@
+iverilog -Wimplict -Wportbind -y ../sdr_lib -y ../models -y . -y ../control_lib/ -y ../fifo -y ../coregen -y /opt/Xilinx/10.1/ISE/verilog/src/XilinxCoreLib -y /opt/Xilinx/10.1/ISE/verilog/src/unisims/ -y ../timing -o vita_tx_tb vita_tx_tb.v
diff --git a/fpga/usrp2/vrt/vita_tx_chain.v b/fpga/usrp2/vrt/vita_tx_chain.v
new file mode 100644
index 000000000..82a43d57a
--- /dev/null
+++ b/fpga/usrp2/vrt/vita_tx_chain.v
@@ -0,0 +1,162 @@
+//
+// 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/>.
+//
+
+
+module vita_tx_chain
+ #(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,
+ parameter USE_TRANS_HEADER=0,
+ 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 [31:0] sample, input strobe,
+ output underrun, output run, output clear_o,
+ output [31:0] debug);
+
+ localparam MAXCHAN = 1;
+ localparam FIFOWIDTH = 5+64+16+(32*MAXCHAN);
+
+ wire [FIFOWIDTH-1:0] tx1_data;
+ wire tx1_src_rdy, tx1_dst_rdy;
+ wire [31:0] streamid, message;
+ wire trigger, sent;
+ wire [31:0] debug_vtc, debug_vtd, debug_tx_dsp;
+
+ wire error, packet_consumed, ack;
+ wire [31:0] error_code;
+ wire clear_seqnum;
+ wire [31:0] current_seqnum;
+
+ wire clear, flush;
+ assign clear_o = clear;
+ assign underrun = error;
+ assign message = error_code;
+
+ setting_reg #(.my_addr(BASE+0), .width(1)) sr
+ (.clk(clk),.rst(reset),.strobe(set_stb),.addr(set_addr),
+ .in(set_data),.out(flush),.changed(clear));
+
+ 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));
+
+ //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), .clear_seqnum(clear_seqnum),
+ .set_stb(set_stb),.set_addr(set_addr),.set_data(set_data),
+ .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), .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), .run(run), .strobe(strobe), .packet_consumed(packet_consumed),
+ .debug(debug_vtc) );
+
+ 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),
+ .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)) 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),
+ .trigger((error|ack) & (REPORT_ERROR==1)), .sent(),
+ .streamid(streamid), .vita_time(vita_time), .message(message),
+ .seqnum(current_seqnum),
+ .data_o(err_data_int), .src_rdy_o(err_src_rdy_int), .dst_rdy_i(err_dst_rdy_int));
+
+ assign debug = debug_vtc | debug_vtd;
+
+ fifo36_mux #(.prio(1)) mux_err_and_flow // Priority to err messages
+ (.clk(clk), .reset(reset), .clear(0), // Don't clear this or it could get clogged
+ .data0_i(err_data_int), .src0_rdy_i(err_src_rdy_int), .dst0_rdy_o(err_dst_rdy_int),
+ .data1_i(flow_data), .src1_rdy_i(flow_src_rdy), .dst1_rdy_o(flow_dst_rdy),
+ .data_o(err_data_o), .src_rdy_o(err_src_rdy_o), .dst_rdy_i(err_dst_rdy_i));
+
+endmodule // vita_tx_chain
diff --git a/fpga/usrp2/vrt/vita_tx_control.v b/fpga/usrp2/vrt/vita_tx_control.v
new file mode 100644
index 000000000..c3ce2b96a
--- /dev/null
+++ b/fpga/usrp2/vrt/vita_tx_control.v
@@ -0,0 +1,238 @@
+//
+// 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 vita_tx_control
+ #(parameter BASE=0,
+ parameter WIDTH=32)
+ (input clk, input reset, input clear,
+ input set_stb, input [7:0] set_addr, input [31:0] set_data,
+
+ input [63:0] vita_time,
+ output error, output ack,
+ output reg [31:0] error_code,
+ output reg packet_consumed,
+
+ // From vita_tx_deframer
+ input [5+64+16+WIDTH-1:0] sample_fifo_i,
+ input sample_fifo_src_rdy_i,
+ output sample_fifo_dst_rdy_o,
+
+ // To DSP Core
+ output [WIDTH-1:0] sample,
+ output reg run,
+ input strobe,
+
+ output [31:0] debug
+ );
+
+ wire [63:0] send_time = sample_fifo_i[63:0];
+ wire [15:0] seqnum = sample_fifo_i[79:64];
+ wire eop = sample_fifo_i[80];
+ wire eob = sample_fifo_i[81];
+ wire sob = sample_fifo_i[82];
+ wire send_at = sample_fifo_i[83];
+ wire seqnum_err = sample_fifo_i[84];
+
+ wire now, early, late, too_early;
+
+ time_compare
+ time_compare (.time_now(vita_time), .trigger_time(send_time),
+ .now(now), .early(early), .late(late), .too_early(too_early));
+
+ reg late_qual, late_del;
+
+ always @(posedge clk)
+ if(reset | clear)
+ late_del <= 0;
+ else
+ late_del <= late;
+
+ always @(posedge clk)
+ if(reset | clear)
+ late_qual <= 0;
+ else
+ late_qual <= (sample_fifo_src_rdy_i & ~sample_fifo_dst_rdy_o);
+
+ localparam IBS_IDLE = 0;
+ localparam IBS_RUN = 1; // FIXME do we need this?
+ localparam IBS_CONT_BURST = 2;
+ localparam IBS_ERROR = 3;
+ localparam IBS_ERROR_DONE = 4;
+ localparam IBS_ERROR_WAIT = 5;
+
+ wire [31:0] CODE_EOB_ACK = {seqnum,16'd1};
+ wire [31:0] CODE_UNDERRUN = {seqnum,16'd2};
+ wire [31:0] CODE_SEQ_ERROR = {seqnum,16'd4};
+ wire [31:0] CODE_TIME_ERROR = {seqnum,16'd8};
+ wire [31:0] CODE_UNDERRUN_MIDPKT = {seqnum,16'd16};
+ wire [31:0] CODE_SEQ_ERROR_MIDBURST = {seqnum,16'd32};
+
+ reg [2:0] ibs_state;
+
+ wire [31:0] error_policy;
+ setting_reg #(.my_addr(BASE+3)) sr_error_policy
+ (.clk(clk),.rst(reset),.strobe(set_stb),.addr(set_addr),
+ .in(set_data),.out(error_policy),.changed());
+
+ wire policy_wait = error_policy[0];
+ wire policy_next_packet = error_policy[1];
+ wire policy_next_burst = error_policy[2];
+ reg send_error, send_ack;
+
+ always @(posedge clk)
+ if(reset | clear)
+ begin
+ ibs_state <= IBS_IDLE;
+ send_error <= 0;
+ send_ack <= 0;
+ error_code <= 0;
+ end
+ else
+ case(ibs_state)
+ IBS_IDLE :
+ if(sample_fifo_src_rdy_i)
+ if(seqnum_err)
+ begin
+ ibs_state <= IBS_ERROR;
+ error_code <= CODE_SEQ_ERROR;
+ send_error <= 1;
+ end
+ else if(~send_at | now)
+ ibs_state <= IBS_RUN;
+ else if((late_qual & late_del) | too_early)
+ begin
+ ibs_state <= IBS_ERROR;
+ error_code <= CODE_TIME_ERROR;
+ send_error <= 1;
+ end
+
+ IBS_RUN :
+ if(strobe)
+ if(~sample_fifo_src_rdy_i)
+ begin
+ ibs_state <= IBS_ERROR;
+ error_code <= CODE_UNDERRUN_MIDPKT;
+ send_error <= 1;
+ end
+ else if(eop)
+ if(eob)
+ begin
+ ibs_state <= IBS_ERROR_DONE; // Not really an error
+ error_code <= CODE_EOB_ACK;
+ send_ack <= 1;
+ end
+ else
+ ibs_state <= IBS_CONT_BURST;
+
+ IBS_CONT_BURST :
+ if(strobe)
+ begin
+ if(policy_next_packet)
+ ibs_state <= IBS_ERROR_DONE;
+ else if(policy_wait)
+ ibs_state <= IBS_ERROR_WAIT;
+ else
+ ibs_state <= IBS_ERROR;
+ error_code <= CODE_UNDERRUN;
+ send_error <= 1;
+ end
+ else if(sample_fifo_src_rdy_i)
+ if(seqnum_err)
+ begin
+ ibs_state <= IBS_ERROR;
+ error_code <= CODE_SEQ_ERROR_MIDBURST;
+ send_error <= 1;
+ end
+ else
+ ibs_state <= IBS_RUN;
+
+ IBS_ERROR :
+ begin
+ send_error <= 0;
+ if(sample_fifo_src_rdy_i & eop)
+ if(policy_next_packet | (policy_next_burst & eob))
+ ibs_state <= IBS_IDLE;
+ else if(policy_wait)
+ ibs_state <= IBS_ERROR_WAIT;
+ end
+
+ IBS_ERROR_DONE :
+ begin
+ send_error <= 0;
+ send_ack <= 0;
+ ibs_state <= IBS_IDLE;
+ end
+
+ IBS_ERROR_WAIT :
+ send_error <= 0;
+ endcase // case (ibs_state)
+
+
+ assign sample_fifo_dst_rdy_o = (ibs_state == IBS_ERROR) | (strobe & (ibs_state == IBS_RUN)); // FIXME also cleanout
+
+ //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;
+
+ localparam MAX_IDLE = 1000000;
+ // approx 10 ms timeout with a 100 MHz clock, but burning samples will slow that down
+ reg [19:0] countdown;
+
+ always @(posedge clk)
+ if(reset | clear)
+ begin
+ run <= 0;
+ countdown <= 0;
+ end
+ else
+ if (ibs_state == IBS_RUN)
+ if(eob & eop & strobe & sample_fifo_src_rdy_i)
+ run <= 0;
+ else
+ begin
+ run <= 1;
+ countdown <= MAX_IDLE;
+ end
+ else
+ if (countdown == 0)
+ run <= 0;
+ else
+ countdown <= countdown - 1;
+
+ always @(posedge clk)
+ if(reset | clear)
+ packet_consumed <= 0;
+ else
+ packet_consumed <= eop & sample_fifo_src_rdy_i & sample_fifo_dst_rdy_o;
+
+ assign debug = { { now,late_qual,late_del,ack,eop,eob,sob,send_at },
+ { sample_fifo_src_rdy_i, sample_fifo_dst_rdy_o, strobe, run, error, ibs_state[2:0] },
+ { 8'b0 },
+ { 8'b0 } };
+
+endmodule // vita_tx_control
diff --git a/fpga/usrp2/vrt/vita_tx_deframer.v b/fpga/usrp2/vrt/vita_tx_deframer.v
new file mode 100644
index 000000000..ed3916311
--- /dev/null
+++ b/fpga/usrp2/vrt/vita_tx_deframer.v
@@ -0,0 +1,261 @@
+//
+// 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/>.
+//
+
+
+module vita_tx_deframer
+ #(parameter BASE=0,
+ parameter MAXCHAN=1,
+ parameter USE_TRANS_HEADER=0)
+ (input clk, input reset, input clear, input clear_seqnum,
+ input set_stb, input [7:0] set_addr, input [31:0] set_data,
+
+ // To FIFO interface of Buffer Pool
+ input [35:0] data_i,
+ input src_rdy_i,
+ output dst_rdy_o,
+
+ output [5+64+16+(32*MAXCHAN)-1:0] sample_fifo_o,
+ output sample_fifo_src_rdy_o,
+ input sample_fifo_dst_rdy_i,
+
+ output [31:0] current_seqnum,
+
+ // FIFO Levels
+ output [15:0] fifo_occupied,
+ output fifo_full,
+ output fifo_empty,
+ output [31:0] debug
+ );
+
+ localparam FIFOWIDTH = 5+64+16+(32*MAXCHAN);
+
+ wire [1:0] numchan = 0;/*
+ setting_reg #(.my_addr(BASE), .at_reset(0), .width(2)) sr_numchan
+ (.clk(clk),.rst(reset),.strobe(set_stb),.addr(set_addr),
+ .in(set_data),.out(numchan),.changed());
+ */
+
+ reg [3:0] vita_state;
+ wire has_streamid, has_classid, has_secs, has_tics, has_trailer;
+ assign has_streamid = (data_i[31:28]==4'b0001);
+ assign has_classid = data_i[27];
+ assign has_secs = ~(data_i[23:22]==2'b00);
+ assign has_tics = ~(data_i[21:20]==2'b00);
+ assign has_trailer = data_i[26];
+ wire is_sob = data_i[25];
+ wire is_eob = data_i[24];
+ wire eof = data_i[33];
+ reg has_streamid_reg, has_classid_reg, has_secs_reg, has_tics_reg;
+ reg has_trailer_reg, is_sob_reg, is_eob_reg;
+
+ reg [15:0] pkt_len;
+ reg [1:0] vector_phase;
+ wire line_done;
+
+ wire [31:0] seqnum = data_i;
+ reg [31:0] seqnum_reg;
+ wire [31:0] next_seqnum = seqnum_reg + 32'd1;
+ wire [3:0] vita_seqnum = data_i[19:16];
+ reg [3:0] vita_seqnum_reg;
+ wire [3:0] next_vita_seqnum = vita_seqnum_reg[3:0] + 4'd1;
+ reg seqnum_err;
+
+ assign current_seqnum = seqnum_reg;
+
+ // Output FIFO for packetized data
+ localparam VITA_TRANS_HEADER = 0;
+ localparam VITA_HEADER = 1;
+ localparam VITA_STREAMID = 2;
+ localparam VITA_CLASSID = 3;
+ localparam VITA_CLASSID2 = 4;
+ localparam VITA_SECS = 5;
+ localparam VITA_TICS = 6;
+ localparam VITA_TICS2 = 7;
+ localparam VITA_PAYLOAD = 8;
+ localparam VITA_TRAILER = 10;
+ localparam VITA_DUMP = 11;
+
+ wire [15:0] hdr_len = 2 + has_streamid_reg + has_classid_reg + has_classid_reg + has_secs_reg +
+ has_tics_reg + has_tics_reg + has_trailer_reg;
+
+ wire vita_eof = (pkt_len==hdr_len);
+ wire eop = eof | vita_eof; // FIXME would ignoring eof allow larger VITA packets?
+ wire fifo_space;
+
+ always @(posedge clk)
+ if(reset | clear | clear_seqnum)
+ begin
+ seqnum_reg <= 32'hFFFF_FFFF;
+ vita_seqnum_reg <= 4'hF;
+ end
+ else
+ begin
+ if((vita_state==VITA_TRANS_HEADER) & src_rdy_i)
+ seqnum_reg <= seqnum;
+ if((vita_state==VITA_HEADER) & src_rdy_i)
+ vita_seqnum_reg <= vita_seqnum;
+ end // else: !if(reset | clear_seqnum)
+
+ always @(posedge clk)
+ if(reset | clear)
+ begin
+ vita_state <= (USE_TRANS_HEADER==1) ? VITA_TRANS_HEADER : VITA_HEADER;
+ {has_streamid_reg, has_classid_reg, has_secs_reg, has_tics_reg, has_trailer_reg, is_sob_reg, is_eob_reg}
+ <= 0;
+ seqnum_err <= 0;
+ end
+ else if(src_rdy_i & dst_rdy_o) begin //valid read
+ case(vita_state)
+ VITA_TRANS_HEADER :
+ begin
+ seqnum_err <= ~(seqnum == next_seqnum);
+ vita_state <= VITA_HEADER;
+ end
+ VITA_HEADER :
+ begin
+ {has_streamid_reg, has_classid_reg, has_secs_reg, has_tics_reg, has_trailer_reg, is_sob_reg, is_eob_reg}
+ <= {has_streamid, has_classid, has_secs, has_tics, has_trailer, is_sob, is_eob};
+ pkt_len <= data_i[15:0];
+ vector_phase <= 0;
+ if(has_streamid)
+ vita_state <= VITA_STREAMID;
+ else if(has_classid)
+ vita_state <= VITA_CLASSID;
+ else if(has_secs)
+ vita_state <= VITA_SECS;
+ else if(has_tics)
+ vita_state <= VITA_TICS;
+ else
+ vita_state <= VITA_PAYLOAD;
+ seqnum_err <= seqnum_err | ~(vita_seqnum == next_vita_seqnum);
+ end // case: VITA_HEADER
+ VITA_STREAMID :
+ if(has_classid_reg)
+ vita_state <= VITA_CLASSID;
+ else if(has_secs_reg)
+ vita_state <= VITA_SECS;
+ else if(has_tics_reg)
+ vita_state <= VITA_TICS;
+ else
+ vita_state <= VITA_PAYLOAD;
+ VITA_CLASSID :
+ vita_state <= VITA_CLASSID2;
+ VITA_CLASSID2 :
+ if(has_secs_reg)
+ vita_state <= VITA_SECS;
+ else if(has_tics_reg)
+ vita_state <= VITA_TICS;
+ else
+ vita_state <= VITA_PAYLOAD;
+ VITA_SECS :
+ if(has_tics_reg)
+ vita_state <= VITA_TICS;
+ else
+ vita_state <= VITA_PAYLOAD;
+ VITA_TICS :
+ vita_state <= VITA_TICS2;
+ VITA_TICS2 :
+ vita_state <= VITA_PAYLOAD;
+
+ 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;
+ else
+ vita_state <= VITA_DUMP;
+ VITA_DUMP :
+ if(eof)
+ vita_state <= (USE_TRANS_HEADER==1) ? VITA_TRANS_HEADER : VITA_HEADER;
+ default :
+ vita_state <= (USE_TRANS_HEADER==1) ? VITA_TRANS_HEADER : VITA_HEADER;
+ endcase // case (vita_state)
+
+ end //valid read
+
+ assign line_done = (MAXCHAN == 1)? 1 : (vector_phase == numchan);
+
+ wire [FIFOWIDTH-1:0] fifo_i;
+ reg [63:0] send_time;
+
+ always @(posedge clk)
+ case(vita_state)
+ 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(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) );
+
+ //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
+
+ // 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 },
+ { eof, line_done, store, fifo_space, src_rdy_i, dst_rdy_o, vector_phase[1:0] },
+ { has_secs_reg, is_sob_reg, is_eob_reg, eop, vita_state[3:0] } };
+
+endmodule // vita_tx_deframer
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/fpga/usrp2/vrt/vita_tx_tb.v b/fpga/usrp2/vrt/vita_tx_tb.v
new file mode 100644
index 000000000..b686a8a16
--- /dev/null
+++ b/fpga/usrp2/vrt/vita_tx_tb.v
@@ -0,0 +1,193 @@
+//
+// 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 vita_tx_tb;
+
+ localparam DECIM = 8'd4;
+ localparam INTERP = 8'd4;
+
+ localparam MAXCHAN=1;
+ localparam NUMCHAN=1;
+
+ reg clk = 0;
+ reg reset = 1;
+
+ initial #1000 reset = 0;
+ always #50 clk = ~clk;
+
+ initial $dumpfile("vita_tx_tb.vcd");
+ initial $dumpvars(0,vita_tx_tb);
+
+ wire [(MAXCHAN*32)-1:0] sample, sample_tx;
+ wire strobe, run;
+ reg [35:0] data_o = 36'h0;
+ reg src_rdy = 0;
+ wire dst_rdy;
+
+ wire [63:0] vita_time;
+
+ reg set_stb = 0;
+ reg [7:0] set_addr;
+ reg [31:0] set_data;
+ wire set_stb_dsp;
+ wire [7:0] set_addr_dsp;
+ wire [31:0] set_data_dsp;
+
+ wire sample_dst_rdy, sample_src_rdy;
+ wire [5+64+16+(MAXCHAN*32)-1:0] sample_data_o, sample_data_tx;
+
+ time_64bit #(.TICKS_PER_SEC(100000000), .BASE(0)) time_64bit
+ (.clk(clk), .rst(reset),
+ .set_stb(set_stb), .set_addr(set_addr), .set_data(set_data),
+ .pps(0), .vita_time(vita_time));
+
+ wire [35:0] data_tx;
+ wire src_rdy_tx, dst_rdy_tx;
+ wire sample_dst_rdy_tx, sample_src_rdy_tx;
+
+ fifo_long #(.WIDTH(36)) fifo_short
+ (.clk(clk), .reset(reset), .clear(0),
+ .datain(data_o), .src_rdy_i(src_rdy), .dst_rdy_o(dst_rdy),
+ .dataout(data_tx), .src_rdy_o(src_rdy_tx), .dst_rdy_i(dst_rdy_tx));
+
+ vita_tx_deframer #(.BASE(16), .MAXCHAN(MAXCHAN), .USE_TRANS_HEADER(0)) vita_tx_deframer
+ (.clk(clk), .reset(reset), .clear(0), .clear_seqnum(0),
+ .set_stb(set_stb), .set_addr(set_addr), .set_data(set_data),
+ .data_i(data_tx), .dst_rdy_o(dst_rdy_tx), .src_rdy_i(src_rdy_tx),
+ .sample_fifo_o(sample_data_tx),
+ .sample_fifo_dst_rdy_i(sample_dst_rdy_tx), .sample_fifo_src_rdy_o(sample_src_rdy_tx),
+ .fifo_occupied(), .fifo_full(), .fifo_empty() );
+
+ vita_tx_control #(.BASE(16), .WIDTH(MAXCHAN*32)) vita_tx_control
+ (.clk(clk), .reset(reset), .clear(0),
+ .set_stb(set_stb), .set_addr(set_addr), .set_data(set_data),
+ .vita_time(vita_time), .error(underrun), .error_code(),
+ .sample_fifo_i(sample_data_tx),
+ .sample_fifo_dst_rdy_o(sample_dst_rdy_tx), .sample_fifo_src_rdy_i(sample_src_rdy_tx),
+ .sample(sample_tx), .run(run_tx), .strobe(strobe_tx));
+
+ tx_dsp_model tx_dsp_model
+ (.clk(clk), .reset(reset), .run(run_tx), .interp(INTERP), .strobe(strobe_tx), .sample(sample_tx[31:0] ));
+
+ task write_setting;
+ input [7:0] addr;
+ input [31:0] data;
+ begin
+ set_stb <= 0;
+ @(posedge clk);
+ set_addr <= addr;
+ set_data <= data;
+ set_stb <= 1;
+ @(posedge clk);
+ set_stb <= 0;
+ end
+ endtask // write_setting
+
+ initial
+ begin
+ @(negedge reset);
+ @(posedge clk);
+ write_setting(4,32'h14900008); // VITA header
+ write_setting(5,32'hF00D1234); // VITA streamid
+ write_setting(6,32'h98765432); // VITA trailer
+ write_setting(7,8); // Samples per VITA packet
+ write_setting(8,NUMCHAN); // Samples per VITA packet
+ #10000;
+ queue_vita_packets(0, 32'h300, 5, 32'h0000_1000, 32'h0, 4'h0, 1, 0, 1);
+ queue_vita_packets(0, 32'h0, 5, 32'h0000_2000, 32'h0, 4'h1, 0, 0, 0);
+ queue_vita_packets(0, 32'h0, 5, 32'h0000_3000, 32'h0, 4'h2, 0, 0, 0);
+
+ queue_vita_packets(0, 32'h400, 3, 32'h0000_4000, 32'h0, 4'h3, 1, 0, 1);
+ queue_vita_packets(0, 32'h0, 3, 32'h0000_5000, 32'h0, 4'h4, 0, 0, 0);
+ queue_vita_packets(0, 32'h0, 3, 32'h0000_6000, 32'h0, 4'h5, 0, 1, 0);
+
+ #300000 $finish;
+ end
+
+ task queue_vita_packets;
+ input [31:0] send_secs;
+ input [31:0] sendtime;
+ input [15:0] samples;
+ input [15:0] word;
+ input [31:0] trailer;
+ input [3:0] seqnum;
+ input sob;
+ input eob;
+ input sendat;
+
+ reg [15:0] i;
+
+ begin
+ src_rdy <= 0;
+ @(posedge clk);
+ src_rdy <= 1;
+ data_o <= {4'b0001,4'h0,1'b0,|trailer,sob,eob,{2{sendat}},1'b0,sendat,seqnum,(16'd1+samples+|trailer+sendat+sendat+sendat)}; // header
+ @(posedge clk);
+ //data_o <= {4'b0000,32'h0}; // streamid
+ //@(posedge clk);
+ if(sendat)
+ begin
+ data_o <= {4'b0000,send_secs}; // SECS
+ @(posedge clk);
+ data_o <= {4'b0000,32'h0}; // TICS
+ @(posedge clk);
+ data_o <= {4'b0000,sendtime}; // TICS
+ @(posedge clk);
+ end
+ for(i=0;i<samples-1;i=i+1)
+ begin
+ data_o <= {4'b0000,i,word}; // Payload
+ @(posedge clk);
+ end
+ if(trailer==0)
+ begin
+ data_o <= {4'b0010,i,16'hBEEF}; // Last Payload
+ @(posedge clk);
+ end
+ else
+ begin
+ data_o <= {4'b0000,i,16'hBEEF}; // Last Payload
+ @(posedge clk);
+ data_o <= {4'b0010,trailer}; // Last Payload
+ @(posedge clk);
+ end
+ src_rdy <= 0;
+ @(posedge clk);
+
+ end
+ endtask // queue_vita_packets
+
+endmodule // vita_tx_tb
+
+
+module tx_dsp_model
+ (input clk, input reset,
+ input run,
+ input [7:0] interp,
+ output strobe,
+ input [31:0] sample);
+
+ cic_strober strober(.clock(clk), .reset(reset), .enable(run), .rate(interp), .strobe_fast(1), .strobe_slow(strobe));
+
+ always @(posedge clk)
+ if(strobe)
+ $display("Time %d, Sent Sample %x",$time,sample);
+
+
+endmodule // tx_dsp_model