diff options
Diffstat (limited to 'fpga/usrp2/vrt')
| -rw-r--r-- | fpga/usrp2/vrt/.gitignore | 4 | ||||
| -rw-r--r-- | fpga/usrp2/vrt/Makefile.srcs | 18 | ||||
| -rw-r--r-- | fpga/usrp2/vrt/gen_context_pkt.v | 108 | ||||
| -rw-r--r-- | fpga/usrp2/vrt/trigger_context_pkt.v | 69 | ||||
| -rw-r--r-- | fpga/usrp2/vrt/vita_pkt_gen.v | 59 | ||||
| -rwxr-xr-x | fpga/usrp2/vrt/vita_rx.build | 1 | ||||
| -rw-r--r-- | fpga/usrp2/vrt/vita_rx_chain.v | 62 | ||||
| -rw-r--r-- | fpga/usrp2/vrt/vita_rx_control.v | 216 | ||||
| -rw-r--r-- | fpga/usrp2/vrt/vita_rx_framer.v | 226 | ||||
| -rw-r--r-- | fpga/usrp2/vrt/vita_rx_tb.v | 246 | ||||
| -rwxr-xr-x | fpga/usrp2/vrt/vita_tx.build | 1 | ||||
| -rw-r--r-- | fpga/usrp2/vrt/vita_tx_chain.v | 119 | ||||
| -rw-r--r-- | fpga/usrp2/vrt/vita_tx_control.v | 231 | ||||
| -rw-r--r-- | fpga/usrp2/vrt/vita_tx_deframer.v | 249 | ||||
| -rw-r--r-- | fpga/usrp2/vrt/vita_tx_tb.v | 193 | 
15 files changed, 1802 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..166ed44ef --- /dev/null +++ b/fpga/usrp2/vrt/Makefile.srcs @@ -0,0 +1,18 @@ +# +# 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 \ +)) diff --git a/fpga/usrp2/vrt/gen_context_pkt.v b/fpga/usrp2/vrt/gen_context_pkt.v new file mode 100644 index 000000000..bdfca8237 --- /dev/null +++ b/fpga/usrp2/vrt/gen_context_pkt.v @@ -0,0 +1,108 @@ +// +// 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_SECS = 4; +   localparam CTXT_TICS = 5; +   localparam CTXT_TICS2 = 6; +   localparam CTXT_MESSAGE = 7; +   localparam CTXT_FLOWCTRL = 8; +   localparam CTXT_DONE = 9; + +   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'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_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_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..1986743b3 --- /dev/null +++ b/fpga/usrp2/vrt/vita_rx_chain.v @@ -0,0 +1,62 @@ +// +// Copyright 2011 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program.  If not, see <http://www.gnu.org/licenses/>. +// + + +module vita_rx_chain +  #(parameter BASE=0, +    parameter UNIT=0, +    parameter FIFOSIZE=10, +    parameter PROT_ENG_FLAGS=1) +   (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, +    input [31:0] sample, output run, input strobe, +    output [35:0] rx_data_o, output rx_src_rdy_o, input rx_dst_rdy_i, +    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; +    +   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) ); + +   dsp_framer36 #(.BUF_SIZE(FIFOSIZE),  +		  .PORT_SEL(UNIT),  +		  .PROT_ENG_FLAGS(PROT_ENG_FLAGS)) dsp0_framer36 +     (.clk(clk), .reset(reset), .clear(clear), +      .data_i(rx_data_int), .src_rdy_i(rx_src_rdy_int), .dst_rdy_o(rx_dst_rdy_int), +      .data_o(rx_data_o), .src_rdy_o(rx_src_rdy_o), .dst_rdy_i(rx_dst_rdy_i) ); + +   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..39f32d7fe --- /dev/null +++ b/fpga/usrp2/vrt/vita_rx_control.v @@ -0,0 +1,216 @@ +// +// 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 [28:0] 	  numlines_pre; +   wire 	  send_imm_pre, chain_pre, reload_pre; +   reg 		  send_imm, chain, reload; +   wire 	  read_ctrl, not_empty_ctrl, write_ctrl; +   reg 		  sc_pre2; +   wire [33:0] 	  fifo_line; +   reg [28: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,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 & (numlines_pre==0))); +   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 too_late 	    = late & ~send_imm; +   wire go_now 		    = now | send_imm; +   wire full 		    = ~sample_fifo_in_rdy; +    +   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; +       end +     else +       case(ibs_state) +	 IBS_IDLE : +	   if(not_empty_ctrl) +	     begin +		lines_left <= numlines_pre; +		lines_total <= numlines_pre; +		rcvtime <= rcvtime_pre; +		if(numlines_pre == 0) +		  ibs_state <= IBS_ZEROLEN; +		else +		  ibs_state <= IBS_WAITING; +		send_imm <= send_imm_pre; +		chain <= chain_pre; +		reload <= reload_pre; +	     end +	 IBS_WAITING : +	   if(go_now) +	     ibs_state <= IBS_RUNNING; +	   else if(too_late) +	     ibs_state <= IBS_LATECMD; +	 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(numlines_pre == 0)  // 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_framer.v b/fpga/usrp2/vrt/vita_rx_framer.v new file mode 100644 index 000000000..bd09315bc --- /dev/null +++ b/fpga/usrp2/vrt/vita_rx_framer.v @@ -0,0 +1,226 @@ +// +// 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_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()); + +   setting_reg #(.my_addr(BASE+8),.width(4), .at_reset(1)) 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_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 +       +   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_SECS : pkt_fifo_line <= {2'b00,vita_time_fifo_o[63:32]}; +       VITA_TICS : pkt_fifo_line <= {2'b00,32'd0}; +       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_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_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_SECS; +	   VITA_PAYLOAD : +	     if(sample_fifo_src_rdy_i) +	       begin +		  if(sample_phase == (numchan-4'd1)) +		    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_SECS, 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 : +	 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-4'd1)) &  +				      ~|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..ac9f08fc8 --- /dev/null +++ b/fpga/usrp2/vrt/vita_tx_chain.v @@ -0,0 +1,119 @@ +// +// 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_chain +  #(parameter BASE_CTRL=0, +    parameter BASE_DSP=0, +    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 [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] 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 		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; + +   wire 		error, packet_consumed, ack; +   wire [31:0] 		error_code; +   wire 		clear_seqnum; +   wire [31:0] 		current_seqnum; +   wire 		strobe_tx; +    +   assign underrun = error; +   assign message = error_code; +    +   setting_reg #(.my_addr(BASE_CTRL+1)) sr +     (.clk(clk),.rst(reset),.strobe(set_stb),.addr(set_addr), +      .in(set_data),.out(),.changed(clear_vita)); + +   setting_reg #(.my_addr(BASE_CTRL+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),  +		      .MAXCHAN(MAXCHAN),  +		      .USE_TRANS_HEADER(USE_TRANS_HEADER))  +   vita_tx_deframer +     (.clk(clk), .reset(reset), .clear(clear_vita), .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), +      .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), +      .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), +      .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), +      .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), +      .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), +      .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..5df89bdbe --- /dev/null +++ b/fpga/usrp2/vrt/vita_tx_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_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; + +   // 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()); + +   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 + +   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); +   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..06ca27767 --- /dev/null +++ b/fpga/usrp2/vrt/vita_tx_deframer.v @@ -0,0 +1,249 @@ +// +// 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_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; +   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_STORE         = 9; +   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((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) +	 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 : +	     if(line_done) +	       begin +		  vector_phase <= 0; +		  vita_state <= VITA_STORE; +	       end +	     else +	       vector_phase <= vector_phase + 1; +	   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; +	   VITA_STORE : +	     ; +	   default : +	     vita_state <= (USE_TRANS_HEADER==1) ? VITA_TRANS_HEADER : VITA_HEADER; +	 endcase // case (vita_state) + +   assign line_done = (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 : +	 send_time[63:32] <= data_i[31:0]; +       VITA_TICS2 : +	 send_time[31:0] <= data_i[31:0]; +     endcase // case (vita_state) +    +   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); +   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 dst_rdy_o = ~(vita_state == VITA_PAYLOAD) & ~((vita_state==VITA_STORE)& ~fifo_space) ; + +   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_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 | 
