//
// Copyright 2014 Ettus Research LLC
// Copyright 2018 Ettus Research, a National Instruments Company
//
// SPDX-License-Identifier: LGPL-3.0-or-later
//

module chdr_16sc_to_8sc
  #(parameter BASE=0)
   (input clk, input reset,
    input set_stb, input [7:0] set_addr, input [31:0] set_data,
    //input side of device
    input [63:0] i_tdata,
    input i_tlast,
    input i_tvalid,
    output i_tready,
    //output side of device
    output reg [63:0] o_tdata,
    output o_tlast,
    output o_tvalid,
    input o_tready,

    output [31:0] debug
    );
   
   //pipeline register
   reg [63:0] 	  hold_tdata;
   //bit assignments
   wire 	  chdr_has_hdr = 1'b1;
   wire 	  chdr_has_time = i_tdata[61];
   wire 	  chdr_has_tlr = 1'b0;

   wire [7:0] 	  rounded_i1;
   wire [7:0] 	  rounded_q1;
   wire [7:0] 	  rounded_i0;
   wire [7:0] 	  rounded_q0;

   wire [7:0] 	  rounded_i2;
   wire [7:0] 	  rounded_q2;
   wire [7:0] 	  rounded_i3;
   wire [7:0] 	  rounded_q3;

   //chdr length calculations
   wire [15:0] 	  chdr_header_lines8 = chdr_has_time? 16 : 8;

   wire [15:0] 	  chdr_almost_payload_lines8 = ((i_tdata[47:32] - chdr_header_lines8) >> 1);

   wire [15:0] 	  chdr_payload_lines8 = chdr_almost_payload_lines8 + chdr_header_lines8;
   wire [15:0] 	  my_newhome;

   wire 	  set_sid;
   
   setting_reg #(.my_addr(BASE), .width(17)) new_destination
     (.clk(clk), .rst(reset), .strobe(set_stb), .addr(set_addr), .in(set_data),
      .out({set_sid, my_newhome[15:0]}));

   localparam HEADER        = 2'd0;//IDLE
   localparam TIME          = 2'd1;
   localparam ODD           = 2'd2;
   localparam EVEN          = 2'd3;
   

   reg [1:0] 		    state;
   


   always @(posedge clk) begin
      if (reset) begin
         state <= HEADER;
	 hold_tdata <= 0;
	end	
  else case(state)

             HEADER: begin
		if (i_tvalid && o_tready) begin
		   state <= (i_tdata[61])? TIME : ODD;
		end

             end

             TIME: begin
		if (i_tvalid && o_tready) begin
		   state <= (i_tlast)? HEADER: ODD;
		   hold_tdata <= i_tdata;
		end
             end

             ODD: begin
		if (i_tvalid && o_tready) begin
		   state <= (i_tlast)? HEADER: EVEN;
		   hold_tdata <= i_tdata;

		end
             end

             EVEN: begin
		if (i_tvalid && o_tready)
		  state <= (i_tlast) ? HEADER: ODD;
		  hold_tdata <= i_tdata;
		
             end
	     	     
	     default: state <= HEADER;
	     
	   endcase
   end
   
   //assign 8 bit i and q signals from this line and last
   
   //new data processing
   round #(.bits_in(16),
	   .bits_out(8))
   round_i2
     (.in(i_tdata[63:48]), 
      .out(rounded_i2[7:0])
	    );

   round #(.bits_in(16),
           .bits_out(8))
   round_q2
     (.in(i_tdata[47:32]),
      .out(rounded_q2[7:0])
      );

   round #(.bits_in(16),
           .bits_out(8))
   round_i3
     (.in(i_tdata[31:16]),
      .out(rounded_i3[7:0])
      );

   round #(.bits_in(16),
           .bits_out(8))
   round_q3
     (.in(i_tdata[15:0]),
      .out(rounded_q3[7:0])
      );

   // old data processing 
   round #(.bits_in(16),
	   .bits_out(8))
   round_i0(.in(hold_tdata[63:48]), .out(rounded_i0[7:0])
	    );

   round #(.bits_in(16),
           .bits_out(8))
   round_q0
     (.in(hold_tdata[47:32]),
      .out(rounded_q0[7:0])
      );

   round #(.bits_in(16),
           .bits_out(8))
   round_i1
     (.in(hold_tdata[31:16]),
      .out(rounded_i1[7:0])
      );

   round #(.bits_in(16),
           .bits_out(8))
   round_q1
     (.in(hold_tdata[15:0]),
      .out(rounded_q1[7:0])
      );
   
   // main mux
   always @(*) 
     case(state)
       HEADER: o_tdata = {i_tdata[63:48], chdr_payload_lines8,
			  set_sid ? {i_tdata[15:0], my_newhome[15:0]}:i_tdata[31:0]};
       TIME: o_tdata = i_tdata;
       ODD: o_tdata = {rounded_i2, rounded_q2, rounded_i3, rounded_q3,rounded_i0, rounded_q0, rounded_i1, rounded_q1};
       EVEN: o_tdata = {rounded_i0, rounded_q0, rounded_i1, rounded_q1,rounded_i2, rounded_q2, rounded_i3, rounded_q3};
       default : o_tdata = i_tdata;
     endcase
   
   assign o_tvalid = i_tvalid && (state != ODD || i_tlast);
   assign i_tready = o_tready || (state == ODD && !i_tlast);
   assign o_tlast  = i_tlast;

endmodule












