From ac35b413a595617c1fa57766758c06ccfe3f320e Mon Sep 17 00:00:00 2001
From: Matt Ettus <matt@ettus.com>
Date: Sun, 29 Jan 2012 18:23:23 -0800
Subject: dsp: 8 to 16 bit conversion for tx side.  believed to be functional

---
 usrp2/control_lib/double_buffer_tb.v |  48 ++++++---
 usrp2/sdr_lib/dspengine_8to16.v      | 194 +++++++++++++++++++++++++++++++++++
 2 files changed, 230 insertions(+), 12 deletions(-)
 create mode 100644 usrp2/sdr_lib/dspengine_8to16.v

diff --git a/usrp2/control_lib/double_buffer_tb.v b/usrp2/control_lib/double_buffer_tb.v
index a9aae6956..3e0b04b8a 100644
--- a/usrp2/control_lib/double_buffer_tb.v
+++ b/usrp2/control_lib/double_buffer_tb.v
@@ -46,9 +46,9 @@ module double_buffer_tb();
       .data_i(data_i), .src_rdy_i(src_rdy_i), .dst_rdy_o(dst_rdy_o),
       .data_o(data_o), .src_rdy_o(src_rdy_o), .dst_rdy_i(dst_rdy_i));
 
-   dspengine_16to8 dspengine_16to8
+   dspengine_8to16 dspengine_8to16
      (.clk(clk),.reset(rst),.clear(0),
-      .set_stb(set_stb), .set_addr(0), .set_data({13'h0,1'b1,18'h00400}),
+      .set_stb(set_stb), .set_addr(0), .set_data(1),
       .access_we(access_we), .access_stb(access_stb), .access_ok(access_ok), .access_done(access_done), 
       .access_skip_read(access_skip_read), .access_adr(access_adr), .access_len(access_len), 
       .access_dat_i(buf_to_dsp), .access_dat_o(dsp_to_buf));
@@ -69,7 +69,7 @@ module double_buffer_tb();
 	@(posedge clk);
 	@(posedge clk);
 	@(posedge clk);
-
+/*
 	// Passthrough
 	$display("Passthrough");
 	src_rdy_i <= 1;
@@ -86,12 +86,12 @@ module double_buffer_tb();
 
 	repeat (5)
 	  @(posedge clk);
-
+*/
 	$display("Enabled");
 	set_stb <= 1;
 	@(posedge clk);
 	set_stb <= 0;
-
+/*
 	@(posedge clk);
 	$display("Non-IF Data Passthrough");
 	src_rdy_i <= 1;
@@ -159,23 +159,23 @@ module double_buffer_tb();
 
 	while(~dst_rdy_o)
 	  @(posedge clk);
-
+*/
 	$display("No StreamID, Trailer, Even");
 	src_rdy_i <= 1;
   	data_i <= { 2'b00,1'b0,1'b1,32'h0400FFFF};
 	@(posedge clk);
-	data_i <= { 2'b00,1'b0,1'b0,32'h21002200};
+	data_i <= { 2'b00,1'b0,1'b0,32'h21222324};
 	@(posedge clk);
-	data_i <= { 2'b00,1'b0,1'b0,32'h23002400};
+	data_i <= { 2'b00,1'b0,1'b0,32'h25262728};
 	src_rdy_i <= 0;
 	@(posedge clk);
 	src_rdy_i <= 1;
 	@(posedge clk);
-	data_i <= { 2'b00,1'b0,1'b0,32'h25002600};
+	data_i <= { 2'b00,1'b0,1'b0,32'h292a2b2c};
 	@(posedge clk);
-	data_i <= { 2'b00,1'b0,1'b0,32'h27002800};
+	data_i <= { 2'b00,1'b0,1'b0,32'h2d2e2f30};
 	@(posedge clk);
-	data_i <= { 2'b00,1'b1,1'b0,32'h29002a00};
+	data_i <= { 2'b00,1'b1,1'b0,32'hDEADBEEF};
 	@(posedge clk);
 	src_rdy_i <= 0;
 	@(posedge clk);
@@ -183,6 +183,30 @@ module double_buffer_tb();
 	while(~dst_rdy_o)
 	  @(posedge clk);
 
+	$display("No StreamID, Trailer, Odd");
+	src_rdy_i <= 1;
+  	data_i <= { 2'b00,1'b0,1'b1,32'h0400FFFF};
+	@(posedge clk);
+	data_i <= { 2'b00,1'b0,1'b0,32'h21222324};
+	@(posedge clk);
+	data_i <= { 2'b00,1'b0,1'b0,32'h25262728};
+	src_rdy_i <= 0;
+	@(posedge clk);
+	src_rdy_i <= 1;
+	@(posedge clk);
+	data_i <= { 2'b00,1'b0,1'b0,32'h292a2b2c};
+	@(posedge clk);
+	data_i <= { 2'b00,1'b0,1'b0,32'h2d2e2f30};
+	@(posedge clk);
+	data_i <= { 2'b00,1'b1,1'b0,32'hDEBDBF0D};
+	@(posedge clk);
+	src_rdy_i <= 0;
+	@(posedge clk);
+
+	while(~dst_rdy_o)
+	  @(posedge clk);
+
+/*
 	$display("No StreamID, Trailer, Odd");
 	src_rdy_i <= 1;
   	data_i <= { 2'b00,1'b0,1'b1,32'h0400FFFF};
@@ -246,7 +270,7 @@ module double_buffer_tb();
 	@(posedge clk);
 	src_rdy_i <= 0;
 	@(posedge clk);
-
+*/
      end
    
    initial #28000 $finish;
diff --git a/usrp2/sdr_lib/dspengine_8to16.v b/usrp2/sdr_lib/dspengine_8to16.v
new file mode 100644
index 000000000..39cf440f6
--- /dev/null
+++ b/usrp2/sdr_lib/dspengine_8to16.v
@@ -0,0 +1,194 @@
+
+// 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 dspengine_8to16
+  #(parameter BASE = 0,
+    parameter BUF_SIZE = 9)
+   (input clk, input reset, input clear,
+    input set_stb, input [7:0] set_addr, input [31:0] set_data,
+
+    output access_we,
+    output access_stb,
+    input access_ok,
+    output access_done,
+    output access_skip_read,
+    output [BUF_SIZE-1:0] access_adr,
+    input [BUF_SIZE-1:0] access_len,
+    output [35:0] access_dat_o,
+    input [35:0] access_dat_i
+    );
+
+   wire 	 convert;
+   
+   setting_reg #(.my_addr(BASE),.width(1)) sr_8to16
+     (.clk(clk),.rst(reset),.strobe(set_stb),.addr(set_addr),
+      .in(set_data),.out(convert),.changed());
+   
+   reg [3:0] 	 dsp_state;
+   localparam DSP_IDLE = 0;
+   localparam DSP_PARSE_HEADER = 1;
+   localparam DSP_READ = 2;
+   localparam DSP_WRITE_0 = 3;
+   localparam DSP_WRITE_1 = 4;
+   localparam DSP_READ_TRAILER = 5;
+   localparam DSP_WRITE_TRAILER = 6;
+   localparam DSP_WRITE_HEADER = 7;
+   localparam DSP_DONE = 8;
+
+   // Parse VITA header
+   wire 	 is_if_data = (access_dat_i[31:29] == 3'b000);
+   wire 	 has_streamid = access_dat_i[28];
+   wire 	 has_classid = access_dat_i[27];
+   wire 	 has_trailer = access_dat_i[26];
+   // 25:24 reserved, aka SOB/EOB
+   wire 	 has_secs = |access_dat_i[23:22];
+   wire 	 has_tics = |access_dat_i[21:20];
+   wire [3:0] 	 hdr_length = 1 + has_streamid + has_classid + has_classid + has_secs + has_tics + has_tics;
+   reg [15:0] 	 hdr_length_reg;
+ 	 
+   reg 		 odd;
+   
+   reg [BUF_SIZE-1:0] read_adr, write_adr;
+   reg 		      has_trailer_reg;
+   
+   wire 	      last = (read_adr + 1) == (access_len - has_trailer_reg);
+
+   reg [31:0] 	      new_header, new_trailer, trailer_mask;
+   reg [15:0] 	      length;
+   reg 		      wait_for_trailer;
+   reg [15:0] 	      data_in_len, data_out_len;
+
+   reg [7:0] 	      i8_0, q8_0;
+   wire [7:0] 	      i8_1 = access_dat_i[15:8];
+   wire [7:0] 	      q8_1 = access_dat_i[7:0];
+   reg 		      skip;
+   
+
+   always @(posedge clk)
+     { i8_0, q8_0 } <= access_dat_i[31:16];
+   
+   always @(posedge clk)
+     if(reset | clear)
+       dsp_state <= DSP_IDLE;
+     else
+       case(dsp_state)
+	 DSP_IDLE :
+	   begin
+	      read_adr <= 0;
+	      write_adr <= 0;
+	      if(access_ok)
+		dsp_state <= DSP_PARSE_HEADER;
+	   end
+	 
+	 DSP_PARSE_HEADER :
+	   begin
+	      // FIXME is data always valid here?
+
+	      has_trailer_reg <= has_trailer;
+	      new_header[31:16] <= access_dat_i[31:16];
+	      new_header[15:0] <= access_len;
+	      length <= access_len;
+	      hdr_length_reg <= hdr_length;
+	      if(~is_if_data | ~convert | ~has_trailer)
+		// ~convert is valid (16 bit mode) but both ~trailer and ~is_if_data are both
+		// really error conditions on the TX side.  We shouldn't ever see them in the TX chain
+		dsp_state <= DSP_WRITE_HEADER;  
+	      else
+		begin
+		   read_adr <= access_len-1; // point to trailer
+		   dsp_state <= DSP_READ_TRAILER;
+		   wait_for_trailer <= 0;
+		   data_in_len <= access_len - hdr_length - 1;
+		end
+	   end
+	 
+	 DSP_READ_TRAILER :
+	   begin
+	      wait_for_trailer <= 1;
+	      if(wait_for_trailer)
+		dsp_state <= DSP_WRITE_TRAILER;
+	      new_trailer <= access_dat_i[31:0]; // Leave trailer unchanged
+	      odd <= access_dat_i[20] & access_dat_i[8];
+	      data_out_len <= {data_in_len,1'b0} - (access_dat_i[20] & access_dat_i[8]);
+	      write_adr <= hdr_length_reg + {data_in_len,1'b0} - (access_dat_i[20] & access_dat_i[8]);
+	   end
+
+	 DSP_WRITE_TRAILER :
+	   begin
+	      dsp_state <= DSP_READ;
+	      write_adr <= write_adr - 1;
+	      read_adr <= read_adr - 1;
+	      new_header[15:0] <= write_adr + 1; // length = addr of trailer + 1
+	   end
+
+	 DSP_READ :
+	   begin
+	      dsp_state <= DSP_WRITE_1;
+	      read_adr <= read_adr - 1;
+	   end
+
+	 DSP_WRITE_1 :
+	   begin
+	      write_adr <= write_adr - 1;
+	      odd <= 0;
+	      if(write_adr == hdr_length_reg)
+		dsp_state <= DSP_WRITE_HEADER;
+	      else if(odd)
+		dsp_state <= DSP_READ;
+	      else
+		dsp_state <= DSP_WRITE_0;
+	   end
+
+	 DSP_WRITE_0 :
+	   begin
+	      write_adr <= write_adr - 1;
+	      if(write_adr == hdr_length_reg)
+		dsp_state <= DSP_WRITE_HEADER;
+	      else
+		dsp_state <= DSP_READ;
+	   end
+
+	 DSP_WRITE_HEADER :
+	   dsp_state <= DSP_DONE;
+
+	 DSP_DONE :
+	   begin
+	      read_adr <= 0;
+	      write_adr <= 0;
+	      dsp_state <= DSP_IDLE;
+	   end
+       endcase // case (dsp_state)
+
+   assign access_skip_read = 0;
+   assign access_done = (dsp_state == DSP_DONE);
+
+   assign access_stb = 1;
+
+   assign access_we = (dsp_state == DSP_WRITE_HEADER) | 
+		      (dsp_state == DSP_WRITE_TRAILER) |
+		      (dsp_state == DSP_WRITE_0) |
+		      (dsp_state == DSP_WRITE_1);
+   
+   assign access_dat_o = (dsp_state == DSP_WRITE_HEADER) ? { 4'h1, new_header } :
+			 (dsp_state == DSP_WRITE_TRAILER) ? { 4'h2, new_trailer } :
+			 (dsp_state == DSP_WRITE_0) ? { 4'h0, i8_0, 8'd0, q8_0, 8'd0 } :
+			 (dsp_state == DSP_WRITE_1) ? { 4'h0, i8_1, 8'd0, q8_1, 8'd0 } :
+			 34'h0DEADBEEF;
+         
+   assign access_adr = access_we ? write_adr : read_adr;
+      
+endmodule // dspengine_16to8
-- 
cgit v1.2.3