// serialize natural order parallel packet
// valid only, no ready signal (ready=1 assuming)
// changed to use fifo_regout instead of easy fifo

`timescale 1 ps / 1 ps
module result_pack_p2s #(
	parameter DATAWIDTH = 58,
	parameter PACK_MAG = 11 // , 2**11 = 2048
)
(
		input	clk,
		input	reset_n,

		input	parallel_valid,
		input  [DATAWIDTH-1:0] data_lo,
		input  [DATAWIDTH-1:0] data_hi,
		
		output	serial_valid,
		output	[DATAWIDTH-1:0] serial_data,
		output	error //,
);
localparam PACKSIZE = (2 ** PACK_MAG); // 2048

// FIFO output for FIFO_LO (pbuf), and HI
wire [DATAWIDTH-1:0] pbuf_lo, pbuf_hi;

// full/empty flag
wire	full_pbuf_lo, empty_pbuf_lo, full_pbuf_hi, empty_pbuf_hi;

// SerialIFO input (selected) and output (buffered) signal
wire [DATAWIDTH-1:0] p2s_data, sbuf_data;
// wire [DATAWIDTH-1:0] p2sreg_data;
	
// full/empty flag
wire	full_sbuf, empty_sbuf;

// FIFO dataflow control signals
wire	re_pbuf_lo, re_pbuf_hi, we_sbuf, re_sbuf;
// wire	wereg_sbuf;

// error detection logic
wire	ovf_pbuf_lo, udf_pbuf_lo, ovf_pbuf_hi, udf_pbuf_hi, ovf_sbuf, udf_sbuf;

reg	[PACK_MAG-1:0] count_p2s;
reg		sel_p2s_hi_lo; // selector (0-lo, 1-hi)

always @( posedge clk or negedge reset_n )
	if( ~reset_n ) count_p2s <= (PACKSIZE-1);
	else if( re_pbuf_lo | re_pbuf_hi ) // reading from FIFO_HI/LO
		count_p2s <= count_p2s - 1; // down count (0-> max)

always @( posedge clk or negedge reset_n )
	if( ~reset_n ) sel_p2s_hi_lo <= 1'b0;
	else if( re_pbuf_lo | re_pbuf_hi ) // reading from FIFO_HI/LO
		sel_p2s_hi_lo <= ( count_p2s == 0 ) ? ~sel_p2s_hi_lo : sel_p2s_hi_lo;
		
assign	re_pbuf_lo = ( sel_p2s_hi_lo==1'b0 ) ?  ~empty_pbuf_lo : 1'b0 ;
assign	re_pbuf_hi = ( sel_p2s_hi_lo==1'b1 ) ?  ~empty_pbuf_hi : 1'b0 ;
assign	we_sbuf = ( re_pbuf_lo | re_pbuf_hi );
assign	re_sbuf = ( ~empty_sbuf );

fifo_regout #(DATAWIDTH) FIFO_LO (
		.clk(clk),
		.reset_n(reset_n),
		.we(parallel_valid),
		.din(data_lo),
		.re(re_pbuf_lo),
		.dout(pbuf_lo),
		.flags( {full_pbuf_lo, empty_pbuf_lo, ovf_pbuf_lo, udf_pbuf_lo} ) // ,
);

fifo_regout #(DATAWIDTH) FIFO_HI (
		.clk(clk),
		.reset_n(reset_n),
		.we(parallel_valid),
		.din(data_hi),
		.re(re_pbuf_hi),
		.dout(pbuf_hi),
		.flags( {full_pbuf_hi, empty_pbuf_hi, ovf_pbuf_hi, udf_pbuf_hi} ) // ,
);

assign	p2s_data = ( sel_p2s_hi_lo ) ? pbuf_hi : pbuf_lo ;

/*
DELAY #(DATAWIDTH+1, 1) DELP2S (
		.clk(clk),
		.reset_n(reset_n),
		.din( { we_sbuf, p2s_data } ),
		.dout( {wereg_sbuf, p2sreg_data } ) //,
);
*/

fifo_regout #(DATAWIDTH) FIFO_SERIAL (
		.clk(clk),
		.reset_n(reset_n),
		.we(we_sbuf), // (wereg_sbuf), // (we_sbuf),
		.din(p2s_data), // (p2sreg_data), // (p2s_data),
		.re(re_sbuf),
		.dout(sbuf_data),
		.flags( {full_sbuf, empty_sbuf, ovf_sbuf, udf_sbuf} ) // ,
);

assign serial_valid = re_sbuf;
assign serial_data = sbuf_data;

assign error = (|({ovf_pbuf_lo, udf_pbuf_lo, ovf_pbuf_hi, udf_pbuf_hi, ovf_sbuf, udf_sbuf}));

endmodule
 