`timescale 1ns / 1ps

//////////////////////////////////////////////////////////////////////////////////
// Company: Tair
// Engineer: Churbanov S.
// 
// Create Date:     
// Design Name: 
// Module Name:    InterfaceArbiter
// Project Name: 
// Target Devices: 
// Tool versions: 
// Description: 
//
// Dependencies: 
//
// Revision: 
// Revision 0.01 - File Created
// Additional Comments: 
//
//////////////////////////////////////////////////////////////////////////////////
module InterfaceArbiter
#(	
	parameter OUTWORDWIDTH = 24,
	parameter SSPIWORDWIDTH = 24,
	parameter QSPIWORDWIDTH = SSPIWORDWIDTH/4
)
(
	input Rst_i,
	input Clk_i,
	
	input Sck_i,
	input Ss_i,
	
	input Mosi0_i,
	input Mosi1_i,
	input Mosi2_i,
	input Mosi3_i,
	
	output reg TestTrig_o,
	output reg DataVal_o,
	output [OUTWORDWIDTH-1:0] Data_o
);

//================================================================================
//  REG/WIRE

	localparam [1:0] IDLE = 0;
	localparam [1:0] DEL = 1;
	localparam [1:0] DATARX = 2;
	
	reg [OUTWORDWIDTH-1:0] dataRegSSpi;
	reg [OUTWORDWIDTH-1:0] dataRegQSpi;

	reg [OUTWORDWIDTH-1:0] dataRegSSpiR;
	reg [OUTWORDWIDTH-1:0] dataRegQSpiR;
	
	reg [OUTWORDWIDTH-1:0] dataRegSSpiRR;
	reg [OUTWORDWIDTH-1:0] dataRegQSpiRR;

	reg [OUTWORDWIDTH-1:0] captRegSspi;
	
	reg [QSPIWORDWIDTH-1:0] captReg0;
	reg [QSPIWORDWIDTH-1:0] captReg1;
	reg [QSPIWORDWIDTH-1:0] captReg2;
	reg [QSPIWORDWIDTH-1:0] captReg3;
	
	
	reg spiMode;
	reg spiModeSyncA;
	reg spiModeSyncB;
	
	wire dataVal;
	wire dataValNeg;
	reg dataValReg;
	
	reg [OUTWORDWIDTH/4-1:0] ssCnt;
	reg [16:0] wordsCnt;
	// wire [OUTWORDWIDTH/4-1:0] ssCntRstThresh = (spiMode) ? QSPIWORDWIDTH-1:SSPIWORDWIDTH-1;
	
	reg [16:0] wordsNum;
	
	reg [1:0] nextState;
	reg [1:0] currState;
	
	reg rxDone;
//================================================================================
//  ASSIGNMENTS

	
	// assign DataVal_o = dataValReg;
	assign Data_o = (spiModeSyncB)? dataRegQSpi:dataRegSSpi;
	
//================================================================================
//  CODING

	always @(posedge Clk_i) begin 
		if (Rst_i) begin 
			DataVal_o <= 1'b0;
		end
		else begin 
			DataVal_o <= dataValReg;
		end
	end

	always @(posedge Sck_i) begin 
		if (Rst_i) begin 
			captRegSspi <= 0;

			captReg0 <= 0;
			captReg1 <= 0;
			captReg2 <= 0;
			captReg3 <= 0;
		end
		else begin 
			if (!Ss_i) begin 
				captRegSspi <= {captRegSspi[OUTWORDWIDTH-2:0], Mosi0_i};
				
				captReg0 <= {captReg0[QSPIWORDWIDTH-2:0], Mosi0_i};
				captReg1 <= {captReg1[QSPIWORDWIDTH-2:0], Mosi1_i};
				captReg2 <= {captReg2[QSPIWORDWIDTH-2:0], Mosi2_i};
				captReg3 <= {captReg3[QSPIWORDWIDTH-2:0], Mosi3_i};
			end
		end
	end

	always @(*) begin
		if (currState == IDLE && (Data_o[11]& Data_o[8])) begin
			TestTrig_o = 1'b1;
		end
		else begin
			TestTrig_o = 1'b0;
		end
	end

	always @(posedge Sck_i or posedge Ss_i) begin 
		if (Ss_i) begin 
			ssCnt <= 0;
		end
		else begin 
			if (!Ss_i) begin 
				ssCnt <= ssCnt+1; 
			end
		end
	end

	always @(posedge Clk_i) begin
		if (!Rst_i) begin
			if (currState == DATARX) begin
				if (dataVal) begin
					if (wordsCnt == wordsNum-1) begin
						wordsCnt <= 0;
						rxDone <= 1'b1;
					end else begin
						wordsCnt <= wordsCnt+1;
						rxDone <= 1'b0;
					end
				end
			end else begin
				wordsCnt <= 0;
				rxDone <= 1'b0;
			end
		end else begin
			wordsCnt <= 0;
			rxDone <= 1'b0;
		end
	end
	
	always @(posedge Sck_i) begin 
		if (Rst_i) begin 
			spiMode <= 1'b0;
		end
		else begin
			if (currState == IDLE) begin 
				if (ssCnt == 1) begin 
					spiMode <= captRegSspi[0]; 
				end
			end
		end
	end

	always @(posedge Clk_i) begin 
		if (Rst_i) begin 
			spiModeSyncA <= 1'b0;
			spiModeSyncB <= 1'b0;
			dataRegSSpiR <= 0;
			dataRegQSpiR <= 0;
			dataRegSSpiRR <= 0;
			dataRegQSpiRR <= 0;
		end
		else begin 
			spiModeSyncA <= spiMode;
			spiModeSyncB <= spiModeSyncA;
			dataRegSSpiR  <= captRegSspi;
			dataRegQSpiR  <= {captReg0,captReg1,captReg2,captReg3};
			dataRegSSpiRR <= dataRegSSpiR;
			dataRegQSpiRR <= dataRegQSpiR;
		end
	end

	always @(posedge Clk_i) begin
		if (!Rst_i) begin
			dataValReg <= dataVal;
			if (dataVal) begin
				dataRegSSpi <= dataRegSSpiRR;
				dataRegQSpi <= dataRegQSpiRR;
			end 
		end else begin
			dataRegSSpi <= 0;
			dataRegQSpi <= 0;
			dataValReg <= 0;
		end
	end

	always @(posedge Clk_i) begin
		if (!Rst_i) begin
			if (currState == DEL) begin
				if (!spiModeSyncB) begin
					wordsNum <= dataRegSSpiRR[17:1];
				end else begin
					wordsNum <= dataRegQSpiRR[21:19]+dataRegQSpiRR[17:16]+dataRegQSpiRR[15:12]+dataRegQSpiRR[10:9]+dataRegQSpiRR[7:6]+dataRegQSpiRR[4:3]+dataRegQSpiRR[2]+dataRegQSpiRR[1];
				end 
			end
		end else begin
			wordsNum <= 0;
		end
	end 

	always @(posedge Clk_i) begin
		if (Rst_i) begin
			currState <= IDLE;
		end else begin
			currState <= nextState;
		end
	end

	always @(*) begin
		nextState = IDLE;
		case(currState)
		IDLE		:begin
						if (ssCnt == 6)	begin
							nextState = DEL;
						end	else begin
							nextState = IDLE;
						end
					end

		DEL		:begin
						if (dataVal)	begin
							nextState = DATARX;
						end	else begin
							nextState = DEL;
						end
					end

		DATARX		:begin
						if (rxDone) begin
							nextState  = IDLE;
						end	else begin
							nextState  = DATARX;
						end
					end
		endcase
	end

	edgeDetectingSynchronizer#
	( 
		.Length(2),
		.EdgeType("rising")
	) edgeDetectingSynchronizer (		
		.Rst_i(1'b0),	
		.Clk_i(Clk_i),
		.D_i(Ss_i),
		.D_o(dataVal)
	);

	// edgeDetectingSynchronizer#
	// ( 
	// 	.Length(2),
	// 	.EdgeType("falling")
	// ) edgeDetectingSynchronizer2 (		
	// 	.Rst_i(1'b0),	
	// 	.Clk_i(Clk_i),
	// 	.D_i(dataVal),
	// 	.D_o(dataValNeg)
	// );
endmodule