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; // Extension context packets have no trailer
      
   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;

   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:20],pkt_count,vita_pkt_len};
       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'b11,28'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)
       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_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[3: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_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_PAYLOAD));
   
   assign debug_rx  = vita_state;
   
endmodule // rx_control