module dual_fft(
   input clk, 
   input reset_n,
	input [12 : 0] fftpts_in,
	input	[0 : 0] inverse,
	input	sink_valid,
	input	sink_sop,
	input	sink_eop,
	input	[15 : 0] sink_real,
	input	[15 : 0] sink_imag,
	input	[1 : 0] sink_error,
	input	source_ready,        // current version ignoring
   output [12 : 0] fftpts_out,
	output sink_ready,
	output [1 : 0] source_error,
	output source_sop,
	output source_eop,
	output source_valid,
	output [28 : 0] source_real,
	output [28 : 0] source_imag
	);

// connection wires "s2pt" from s2p to pack_tank
wire	[1:0]	s2pt_error;
wire			s2pt_valid, s2pt_ready, s2pt_sop, s2pt_eop;
wire	[15:0] 	s2pt_real_ev, s2pt_imag_ev, s2pt_real_od, s2pt_imag_od;

// connection wires "bst" burst from pack_tank to split_snk_vrhs/parallel fft
wire	[1:0]	bst_error;
wire			bst_valid, bst_ready, bst_sop, bst_eop;
wire	[15:0] 	bst_real_ev, bst_imag_ev, bst_real_od, bst_imag_od;

// connection wires "ats" attribute of tanked sop from TANK_SOP_ATTR to parallel fft
wire	[12:0]	ats_fftpin;
wire	[0:0]	ats_inv;

// connection wires for parallel ffts sink handshakes "snk...od/ev" from split_snk_vrhs
wire		snk_val_ev, snk_rdy_ev, snk_val_od, snk_rdy_od;

// connection wires for parallel ffts source port
wire	[1:0]	p_src_val, p_src_rdy;
wire	c_src_val, c_src_rdy;

// combine and check parallel attribute, sop/eop are same (and combining error)
wire	[11:0] p_fftpout [1:0];
wire	[11:0] c_fftpout;
wire	[1:0]	p_src_sop, p_src_eop;
wire	c_src_sop, c_src_eop;
wire	errchk_p_fftsrc;
wire	[1:0]	p_src_error [1:0];
wire	[1:0]	c_src_error;

// parallel fft output data signals
wire	[27:0] src_real_ev;
wire	[27:0] src_real_od;
wire	[27:0] src_imag_ev;
wire	[27:0] src_imag_od;

// butterfly stage output
wire	b_src_val; // b_src_rdy=1
wire	b_src_sop, b_src_eop;

// buttefly stage data output
wire	[28:0] src_real_lo;
wire	[28:0] src_real_hi;
wire	[28:0] src_imag_lo;
wire	[28:0] src_imag_hi;

// serialized sop/eop not packed (2048x2 -> 4096)
wire	ser_sop, ser_eop;
reg		mask_ser_sop, mask_ser_eop;

fifo_regout #(14,8) TANK_SOP_ATTR ( // fftpts_in, inverse per packet at SOP
		.clk(clk),
		.reset_n(reset_n),
		.we(sink_valid&sink_ready&sink_sop),
		.din({fftpts_in, inverse}),
		.re(bst_valid&bst_ready&bst_sop),
		.dout({ats_fftpin, ats_inv}),
		.flags() // ,
);

splitter_s2p #(32) U_S2PSPLIT ( // DATAWIDTH = 16+16 (splitting data)
	.clk(clk),
	.reset_n(reset_n),

	.snk_valid(sink_valid),
	.snk_ready(sink_ready), // combinational
	.snk_pack( { sink_error, sink_sop, sink_eop, sink_real, sink_imag } ), // snk_data,
	.src_valid(s2pt_valid),
	.src_ready(s2pt_ready),
	.src_pack( { s2pt_error, s2pt_sop, s2pt_eop, 
					s2pt_real_od, s2pt_imag_od, s2pt_real_ev, s2pt_imag_ev } ) // src_data (64bit)
);

pack_tank #(64, 2) U_PACKTANK ( // complex data (16,16) x 2 (od,ev) and 4 paket burst -> changed 2
	.clk(clk),
	.reset_n(reset_n),
	.snk_valid(s2pt_valid),
	.snk_ready(s2pt_ready),
	.snk_pack( { s2pt_error, s2pt_sop, s2pt_eop, 
					s2pt_real_od, s2pt_imag_od, s2pt_real_ev, s2pt_imag_ev } ), 
	.src_valid(bst_valid),
	.src_ready(bst_ready),
	.src_pack( { bst_error, bst_sop, bst_eop, 
					bst_real_od, bst_imag_od, bst_real_ev, bst_imag_ev } ) //, src_error, src_sop, src_eop, src_data
);

split_snk_vrhs U_SPLIT_SNKVRHS
(
	.snk_valid(bst_valid),
	.snk_ready(bst_ready),
	.snk_val_ev(snk_val_ev),
	.snk_rdy_ev(snk_rdy_ev),
	.snk_val_od(snk_val_od),
	.snk_rdy_od(snk_rdy_od) // ,
);

VSFFT2048	U_FFTEVN(
	.clk(clk),
	.reset_n(reset_n),
	.sink_valid(snk_val_ev),
	.sink_ready(snk_rdy_ev),
	.sink_error(bst_error),
	.sink_sop(bst_sop),
	.sink_eop(bst_eop),
	.fftpts_in(ats_fftpin[12:1]),
	.inverse(ats_inv),
	.sink_imag(bst_imag_ev),
	.sink_real(bst_real_ev),
	.source_valid(p_src_val[0]),
	.source_ready(p_src_rdy[0]),
	.source_error(p_src_error[0]),
	.source_sop(p_src_sop[0]),
	.source_eop(p_src_eop[0]),
	.fftpts_out(p_fftpout[0]),
	.source_imag(src_imag_ev),
	.source_real(src_real_ev));


VSFFT2048	U_FFTODD(
	.clk(clk),
	.reset_n(reset_n),
	.sink_valid(snk_val_od),
	.sink_ready(snk_rdy_od),
	.sink_error(bst_error),
	.sink_sop(bst_sop),
	.sink_eop(bst_eop),
	.fftpts_in(ats_fftpin[12:1]),
	.inverse(ats_inv),
	.sink_imag(bst_imag_od),
	.sink_real(bst_real_od),
	.source_valid(p_src_val[1]),
	.source_ready(p_src_rdy[1]),
	.source_error(p_src_error[1]),
	.source_sop(p_src_sop[1]),
	.source_eop(p_src_eop[1]),
	.fftpts_out(p_fftpout[1]),
	.source_imag(src_imag_od),
	.source_real(src_real_od));

combine_src_vrhs #(2) U_COMB_SRCVHRS
(
	.p_src_valid(p_src_val),
	.p_src_ready(p_src_rdy),
	.error_aon_valid(),
	
	.src_valid(c_src_val), // "serial" "combined" valid
	.src_ready(c_src_rdy) //, "serial" "combined" ready
);

assign c_src_rdy = 1'b1; // ready = 1 fixed (temporary)

// combine and error check
assign {c_fftpout, c_src_sop, c_src_eop } = { p_fftpout[0], p_src_sop[0], p_src_eop[0] };
assign errchk_p_fftsrc = (c_src_val & c_src_rdy) ? 
				( { p_fftpout[1], p_src_sop[1], p_src_eop[1] }!={ p_fftpout[0], p_src_sop[0], p_src_eop[0] } ) :
						1'b0;
assign c_src_error = ( p_src_error[0] | p_src_error[1] );

assign c_src_ready = 1'b1; // butterflypart no support ready (back pressure)

butterfly_2048x2 U_BUTTERFLY(
	.clk(clk), 
	.reset_n(reset_n),
   
	.snk_valid(c_src_val),
	.snk_sop(c_src_sop),
	.snk_eop(c_src_eop),
	.snk_real_ev(src_real_ev),
	.snk_imag_ev(src_imag_ev),
	.snk_real_od(src_real_od),
	.snk_imag_od(src_imag_od),

	.src_valid(b_src_val),
	.src_sop(b_src_sop),
	.src_eop(b_src_eop),
	.src_real_lo(src_real_lo),
	.src_imag_lo(src_imag_lo),
	.src_real_hi(src_real_hi),
	.src_imag_hi(src_imag_hi) //,

	);

result_pack_p2s #(60,11) U_RES_PACK_P2S
(
		.clk(clk),
		.reset_n(reset_n),

		.parallel_valid(b_src_val),
		.data_lo( {b_src_sop, b_src_eop, src_real_lo, src_imag_lo} ),
		.data_hi( {b_src_sop, b_src_eop, src_real_hi, src_imag_hi} ),
		
		.serial_valid(source_valid),
		.serial_data( {ser_sop, ser_eop, source_real, source_imag } ),
		.error() //,
);

always @(posedge clk or negedge reset_n)
	if( ~reset_n ) { mask_ser_sop, mask_ser_eop } <= 2'b10 ;
	else if( source_valid ) begin
		mask_ser_sop <= ser_sop ^ mask_ser_sop ; // toggle at sop
		mask_ser_eop <= ser_eop ^ mask_ser_eop ;
	end

assign source_sop = ser_sop & mask_ser_sop;
assign source_eop = ser_eop & mask_ser_eop;

assign source_error = c_src_error;

assign fftpts_out = { c_fftpout, 1'b0 } ; // ignore adjusting latency (7?)

endmodule
