diff options
Diffstat (limited to 'fpga/usrp2/vrt')
| -rw-r--r-- | fpga/usrp2/vrt/.gitignore | 4 | ||||
| -rwxr-xr-x | fpga/usrp2/vrt/vita_rx.build | 1 | ||||
| -rw-r--r-- | fpga/usrp2/vrt/vita_rx_control.v | 180 | ||||
| -rw-r--r-- | fpga/usrp2/vrt/vita_rx_framer.v | 199 | ||||
| -rw-r--r-- | fpga/usrp2/vrt/vita_rx_tb.v | 213 | ||||
| -rwxr-xr-x | fpga/usrp2/vrt/vita_tx.build | 1 | ||||
| -rw-r--r-- | fpga/usrp2/vrt/vita_tx_control.v | 98 | ||||
| -rw-r--r-- | fpga/usrp2/vrt/vita_tx_deframer.v | 187 | ||||
| -rw-r--r-- | fpga/usrp2/vrt/vita_tx_tb.v | 264 | 
9 files changed, 1147 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/vita_rx.build b/fpga/usrp2/vrt/vita_rx.build new file mode 100755 index 000000000..f6d2d75a3 --- /dev/null +++ b/fpga/usrp2/vrt/vita_rx.build @@ -0,0 +1 @@ +iverilog -Wimplict -Wportbind -y ../models -y . -y ../control_lib/ -y ../control_lib/newfifo -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_control.v b/fpga/usrp2/vrt/vita_rx_control.v new file mode 100644 index 000000000..669b8299d --- /dev/null +++ b/fpga/usrp2/vrt/vita_rx_control.v @@ -0,0 +1,180 @@ + +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 [4+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, clear_int, clear_reg; + +   assign clear_int  = clear | clear_reg; +    +   wire [63:0] 	  rcvtime_pre; +   reg [63:0] 	  rcvtime; +   wire [29:0] 	  numlines_pre; +   wire 	  send_imm_pre, chain_pre; +   reg 		  send_imm, chain; +   wire 	  full_ctrl, read_ctrl, empty_ctrl, write_ctrl; +   reg 		  sc_pre2; +   wire [33:0] 	  fifo_line; +   reg [29:0] 	  lines_left; +   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)); +    +   setting_reg #(.my_addr(BASE+3)) sr_clear +     (.clk(clk),.rst(reset),.strobe(set_stb),.addr(set_addr), +      .in(set_data),.out(),.changed(clear_reg)); + +   // FIFO to store commands sent from the settings bus +   always @(posedge clk) +     sc_pre2 		  <= sc_pre1; +   assign      write_ctrl  = sc_pre1 & ~sc_pre2; + +   wire [4:0]  command_queue_len; +   shortfifo #(.WIDTH(96)) commandfifo +     (.clk(clk),.rst(reset),.clear(clear_int), +      .datain({new_command,new_time}), .write(write_ctrl&~full_ctrl), .full(full_ctrl), +      .dataout({send_imm_pre,chain_pre,numlines_pre,rcvtime_pre}),  +      .read(read_ctrl), .empty(empty_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; + +   wire signal_cmd_done     = (lines_left == 1) & (~chain | (~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); + +   // Buffer of samples for while we're writing the packet headers +   wire [3:0] flags = {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)); +    +   fifo_short #(.WIDTH(4+64+WIDTH)) rx_sample_fifo +     (.clk(clk),.reset(reset),.clear(clear_int), +      .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_int) +       begin +	  ibs_state 	   <= IBS_IDLE; +	  lines_left 	   <= 0; +	  rcvtime 	   <= 0; +	  send_imm 	   <= 0; +	  chain 	   <= 0; +       end +     else +       case(ibs_state) +	 IBS_IDLE : +	   if(~empty_ctrl) +	     begin +		lines_left <= numlines_pre; +		rcvtime <= rcvtime_pre; +		ibs_state <= IBS_WAITING; +		send_imm <= send_imm_pre; +		chain <= chain_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(empty_ctrl) +		      ibs_state      <= IBS_BROKENCHAIN; +		    else +		      begin +			 lines_left  <= numlines_pre; +			 rcvtime     <= rcvtime_pre; +			 send_imm    <= send_imm_pre; +			 chain 	     <= chain_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; +       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) ) +     & ~empty_ctrl; +    +   assign debug_rx = { { ibs_state[2:0], command_queue_len }, +		       { 8'd0 }, +		       { go_now, too_late, run, strobe, read_ctrl, write_ctrl, full_ctrl, 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 // 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..f3a81664a --- /dev/null +++ b/fpga/usrp2/vrt/vita_rx_framer.v @@ -0,0 +1,199 @@ + +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 [4+64+(32*MAXCHAN)-1:0] sample_fifo_i, +    input sample_fifo_src_rdy_i, +    output sample_fifo_dst_rdy_o, +     +    // FIFO Levels +    output [15:0] fifo_occupied, +    output fifo_full, +    output fifo_empty, +     +    output [31:0] debug_rx +    ); + +   localparam SAMP_WIDTH  = 4+64+(32*MAXCHAN); +   reg [3:0] 	  sample_phase; +   wire [3:0] 	  numchan; +   wire [3:0] 	  flags_fifo_o = sample_fifo_i[SAMP_WIDTH-1:SAMP_WIDTH-4]; +   wire [63:0] 	  vita_time_fifo_o = sample_fifo_i[SAMP_WIDTH-5:SAMP_WIDTH-68]; + +   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 [3:0] flags = {signal_overrun,signal_brokenchain,signal_latecmd,signal_cmd_done}; + +   wire 	  clear_reg; +   wire 	  clear_int  = clear | clear_reg; + +   setting_reg #(.my_addr(BASE+3)) sr_clear +     (.clk(clk),.rst(reset),.strobe(set_stb),.addr(set_addr), +      .in(set_data),.out(),.changed(clear_reg)); + +   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)) 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), .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; +       +   always @(posedge clk) +     if(reset | clear_pkt_count) +       pkt_count <= 0; +     else if((vita_state == VITA_TRAILER) & pkt_fifo_rdy) +       pkt_count <= pkt_count + 1; + +   always @* +     case(vita_state) +       VITA_HEADER, VITA_ERR_HEADER : pkt_fifo_line <= {2'b01,vita_header[31:20],pkt_count,vita_pkt_len}; +       VITA_STREAMID, VITA_ERR_STREAMID : pkt_fifo_line <= {2'b00,vita_streamid}; +       VITA_SECS, VITA_ERR_SECS : pkt_fifo_line <= {2'b00,vita_time_fifo_o[63:32]}; +       VITA_TICS, VITA_ERR_TICS : pkt_fifo_line <= {2'b00,32'd0}; +       VITA_TICS2, VITA_ERR_TICS2 : pkt_fifo_line <= {2'b00,vita_time_fifo_o[31:0]}; +       VITA_PAYLOAD : pkt_fifo_line <= {2'b00,data_fifo_o}; +       VITA_ERR_PAYLOAD : pkt_fifo_line <= {2'b00,28'd0,flags_fifo_o}; +       VITA_TRAILER : pkt_fifo_line <= {2'b10,vita_trailer}; +       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) +       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[3:1]) +		vita_state <= VITA_ERR_HEADER; +	      else +		vita_state <= VITA_HEADER; +	 end +       else if(pkt_fifo_rdy) +	 case(vita_state) +	   VITA_PAYLOAD : +	     if(sample_fifo_src_rdy_i) +	       begin +		  if(sample_phase == (numchan-4'd1)) +		    begin +		       sample_phase <= 0; +		       sample_ctr   <= sample_ctr + 1; +		       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 +	   VITA_TRAILER, VITA_ERR_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[3:1]); +       VITA_ERR_HEADER, VITA_ERR_STREAMID, VITA_ERR_SECS, VITA_ERR_TICS, VITA_ERR_TICS2, VITA_ERR_PAYLOAD, VITA_ERR_TRAILER : +	 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_int), +      .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(fifo_occupied[4:0]) ); +   assign fifo_occupied[15:5] = 0; +   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[3:1]) | +				     (vita_state==VITA_ERR_TRAILER)); +    +   assign debug_rx  = vita_state; +    +endmodule // rx_control diff --git a/fpga/usrp2/vrt/vita_rx_tb.v b/fpga/usrp2/vrt/vita_rx_tb.v new file mode 100644 index 000000000..b4fda9622 --- /dev/null +++ b/fpga/usrp2/vrt/vita_rx_tb.v @@ -0,0 +1,213 @@ + + +module vita_rx_tb; + +   localparam DECIM  = 8'd4; +   localparam MAXCHAN=4; +   localparam NUMCHAN=4; +    +   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+4+(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'hDEADBEEF);  // 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 +	queue_rx_cmd(1,0,8,32'h0,32'h0);  // send imm, single packet +	queue_rx_cmd(1,0,16,32'h0,32'h0);  // send imm, 2 packets worth +	queue_rx_cmd(1,0,7,32'h0,32'h0);  // send imm, 1 short packet worth +	queue_rx_cmd(1,0,9,32'h0,32'h0);  // send imm, just longer than 1 packet +	 +	queue_rx_cmd(1,1,16,32'h0,32'h0);  // chained +	queue_rx_cmd(0,0,8,32'h0,32'h0);  // 2nd in chain +	 +	queue_rx_cmd(1,1,17,32'h0,32'h0);  // chained, odd length +	queue_rx_cmd(0,0,9,32'h0,32'h0);  // 2nd in chain, also odd length +	 +	queue_rx_cmd(0,0,8,32'h0,32'h340);  // send at, on time +	queue_rx_cmd(0,0,8,32'h0,32'h100);  // send at, but late + +	queue_rx_cmd(1,1,8,32'h0,32'h0);  // chained, but break chain +	#100000; +	$display("\nEnd chain with zero samples, shouldn't error\n"); +	queue_rx_cmd(1,1,8,32'h0,32'h0);  // chained +	queue_rx_cmd(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,14,32'h0,32'h0);  // chained +	queue_rx_cmd(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,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,100,32'h0,32'h0);  // long enough to fill the fifos +	queue_rx_cmd(1,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,100,32'h0,32'h0);  // long enough to fill the fifos +	//queue_rx_cmd(1,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 [29:0] lines; +      input [31:0] secs; +      input [31:0] tics; +      begin +	 write_setting(0,{send_imm,chain,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..902929c08 --- /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 ../control_lib/newfifo -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_control.v b/fpga/usrp2/vrt/vita_tx_control.v new file mode 100644 index 000000000..bffc64e52 --- /dev/null +++ b/fpga/usrp2/vrt/vita_tx_control.v @@ -0,0 +1,98 @@ + +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 underrun, + +    // From vita_tx_deframer +    input [4+64+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 run, +    input strobe, + +    output [31:0] debug +    ); +    +   assign sample = sample_fifo_i[4+64+WIDTH-1:4+64]; + +   wire [63:0] send_time = sample_fifo_i[63:0]; +   wire        eop = sample_fifo_i[64]; +   wire        eob = sample_fifo_i[65]; +   wire        sob = sample_fifo_i[66]; +   wire        send_at = sample_fifo_i[67]; +   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()); +//		   .late(late), .too_early(too_early)); +    +   localparam IBS_IDLE = 0; +   localparam IBS_RUN = 1;  // FIXME do we need this? +   localparam IBS_CONT_BURST = 2; +   localparam IBS_UNDERRUN = 3; +   localparam IBS_UNDERRUN_DONE = 4; +    +   reg [2:0] ibs_state; + +   wire      clear_state; +   setting_reg #(.my_addr(BASE+1)) sr +     (.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr), +      .in(set_data),.out(),.changed(clear_state)); +    +   always @(posedge clk) +     if(reset | clear_state) +       ibs_state <= 0; +     else +       case(ibs_state) +	 IBS_IDLE : +	   if(sample_fifo_src_rdy_i) +	     if(~send_at | now) +	       ibs_state <= IBS_RUN; +	     else if(late | too_early) +	       ibs_state <= IBS_UNDERRUN; +	  +	 IBS_RUN : +	   if(strobe) +	     if(~sample_fifo_src_rdy_i) +	       ibs_state <= IBS_UNDERRUN; +	     else if(eop) +	       if(eob) +		 ibs_state <= IBS_IDLE; +	       else +		 ibs_state <= IBS_CONT_BURST; + +	 IBS_CONT_BURST : +	   if(strobe) +	     ibs_state <= IBS_UNDERRUN_DONE; +	   else if(sample_fifo_src_rdy_i) +	     ibs_state <= IBS_RUN; +	  +	 IBS_UNDERRUN : +	   if(sample_fifo_src_rdy_i & eop) +	     ibs_state <= IBS_UNDERRUN_DONE; + +	 IBS_UNDERRUN_DONE : +	   ; +       endcase // case (ibs_state) + +   assign sample_fifo_dst_rdy_o = (ibs_state == IBS_UNDERRUN) | (strobe & (ibs_state == IBS_RUN));  // FIXME also cleanout +   assign run = (ibs_state == IBS_RUN) | (ibs_state == IBS_CONT_BURST); +   assign underrun = (ibs_state == IBS_UNDERRUN_DONE); + +   assign debug = { { now,early,late,too_early,eop,eob,sob,send_at }, +		    { sample_fifo_src_rdy_i, sample_fifo_dst_rdy_o, strobe, run, underrun, 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..49428ead5 --- /dev/null +++ b/fpga/usrp2/vrt/vita_tx_deframer.v @@ -0,0 +1,187 @@ + +module vita_tx_deframer +  #(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 +    input [35:0] data_i, +    input src_rdy_i, +    output dst_rdy_o, +     +    output [4+64+(32*MAXCHAN)-1:0] sample_fifo_o, +    output sample_fifo_src_rdy_o, +    input sample_fifo_dst_rdy_i, +     +    // FIFO Levels +    output [15:0] fifo_occupied, +    output fifo_full, +    output fifo_empty, +    output [31:0] debug +    ); + +   wire [1:0] numchan; +   setting_reg #(.my_addr(BASE), .at_reset(0)) 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'b001); +   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]; +   assign is_sob = data_i[25]; +   assign 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; +    +   // Output FIFO for packetized data +   localparam VITA_HEADER 	 = 0; +   localparam VITA_STREAMID 	 = 1; +   localparam VITA_CLASSID 	 = 2; +   localparam VITA_CLASSID2 	 = 3; +   localparam VITA_SECS 	 = 4; +   localparam VITA_TICS 	 = 5; +   localparam VITA_TICS2 	 = 6; +   localparam VITA_PAYLOAD 	 = 7; +   localparam VITA_STORE         = 8; +   localparam VITA_TRAILER 	 = 9; + +   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        eop = eof | (pkt_len==hdr_len);  // FIXME would ignoring eof allow larger VITA packets? +   wire        fifo_space; +    +   always @(posedge clk) +     if(reset | clear) +       begin +	  vita_state 		<= VITA_HEADER; +	  {has_streamid_reg, has_classid_reg, has_secs_reg, has_tics_reg, has_trailer_reg, is_sob_reg, is_eob_reg}  +	    <= 0; +       end +     else  +       if((vita_state == VITA_STORE) & fifo_space) +	 if(eop)   +	   if(has_trailer_reg) +	     vita_state <= VITA_TRAILER; +	   else +	     vita_state <= VITA_HEADER; +	 else +	   begin +	      vita_state <= VITA_PAYLOAD; +	      pkt_len <= pkt_len - 1; +	   end +       else if(src_rdy_i) +	 case(vita_state) +	   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; +	     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 : +	     vita_state <= VITA_HEADER; +	   VITA_STORE : +	     ; +	   default : +	     vita_state <= VITA_HEADER; +	 endcase // case (vita_state) + +   assign line_done = (vector_phase == numchan); +    +   wire [4+64+32*MAXCHAN-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]; +       VITA_STORE, VITA_HEADER : +	 send_time[63:0] <= 64'd0; +     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(4+64+32*MAXCHAN)) 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,has_secs_reg,is_sob_reg,is_eob_reg,eop,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..90986a35f --- /dev/null +++ b/fpga/usrp2/vrt/vita_tx_tb.v @@ -0,0 +1,264 @@ + + +module vita_tx_tb; + +   localparam DECIM  = 8'd4; +   localparam INTERP = 8'd4; +    +   localparam MAXCHAN=4; +   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; +   wire [35:0] data_o; +   wire        src_rdy; +   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; + +   /* +   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+4+(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)); +    +   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 +    +   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() ); + +   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)) vita_tx_deframer +     (.clk(clk), .reset(reset), .clear(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-100), .underrun(underrun), +      .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] )); + +   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'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_rx_cmd(1,0,8,32'h0,32'h0);  // send imm, single packet +/* + 	queue_rx_cmd(1,0,16,32'h0,32'h0);  // send imm, 2 packets worth +	queue_rx_cmd(1,0,7,32'h0,32'h0);  // send imm, 1 short packet worth +	queue_rx_cmd(1,0,9,32'h0,32'h0);  // send imm, just longer than 1 packet +	 +	queue_rx_cmd(1,1,16,32'h0,32'h0);  // chained +	queue_rx_cmd(0,0,8,32'h0,32'h0);  // 2nd in chain +	 +	queue_rx_cmd(1,1,17,32'h0,32'h0);  // chained, odd length +	queue_rx_cmd(0,0,9,32'h0,32'h0);  // 2nd in chain, also odd length +	 +	queue_rx_cmd(0,0,8,32'h0,32'h340);  // send at, on time +	queue_rx_cmd(0,0,8,32'h0,32'h100);  // send at, but late + +	queue_rx_cmd(1,1,8,32'h0,32'h0);  // chained, but break chain +	#100000; +	$display("\nEnd chain with zero samples, shouldn't error\n"); +	queue_rx_cmd(1,1,8,32'h0,32'h0);  // chained +	queue_rx_cmd(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,14,32'h0,32'h0);  // chained +	queue_rx_cmd(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,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,100,32'h0,32'h0);  // long enough to fill the fifos +	queue_rx_cmd(1,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,100,32'h0,32'h0);  // long enough to fill the fifos +	//queue_rx_cmd(1,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 [29:0] lines; +      input [31:0] secs; +      input [31:0] tics; +      begin +	 write_setting(0,{send_imm,chain,lines}); +	 write_setting(1,secs); +	 write_setting(2,tics); +      end +   endtask // queue_rx_cmd +    +endmodule // vita_tx_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 + +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  | 
