`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,
	
	
	input DataVal_o,
	input [OUTWORDWIDTH-1:0] Data_o
);

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

	localparam [1:0] IDLE = 0;
	localparam [1:0] DATARX = 1;
	
	reg [OUTWORDWIDTH-1:0] dataRegSSpi;
	reg [OUTWORDWIDTH-1:0] dataRegQSpi;
	
	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 ssReg;
	reg ssRegR;
	reg ssRegRR;
	
	reg spiMode;
	
	wire ssPos;
	reg ssPosR;
	
	reg dataValReg;
	
	reg [OUTWORDWIDTH/4-1:0] ssCnt;
	reg [OUTWORDWIDTH/4-1: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 ssPos = ssRegR & !ssRegRR;

	
	assign DataVal_o = dataValReg;
	assign Data_o = (spiMode)? dataRegQSpi:dataRegSSpi;
	
//================================================================================
//  CODING
	always @(posedge Sck_i) begin
		if (!Rst_i) 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 else begin
			captRegSspi <= 0;
				
			captReg0 <= 0;
			captReg1 <= 0;
			captReg2 <= 0;
			captReg3 <= 0;
		end
	end
	
	always @(posedge Sck_i) begin
		if (!Rst_i) begin
			if (!Ss_i) begin
				if (ssCnt == ssCntRstThresh) begin
					ssCnt <= 0;
				end else begin
					ssCnt <= ssCnt+1;
				end
			end
		end else begin
			ssCnt <= 0;
		end
	end
	
	always @(posedge Clk_i) begin
		if (!Rst_i) begin
			if (currState == DATARX) begin
				if (ssPos) 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 Clk_i) begin
		if (!Rst_i) begin
			if (currState == IDLE) begin
				if (ssCnt == 1) begin
					if (captRegSspi[0]) begin
						spiMode <= 1'b1;	//quad
					end else begin
						spiMode <= 1'b0;	//single
					end
				end
			end
		end else begin
			spiMode <= 1'b0;
		end
	end 
	
	always @(posedge Clk_i) begin
		if (!Rst_i) begin
			if (currState == IDLE) begin
				if (!spiMode) begin
					wordsNum <= dataRegSSpi[17:1];
				end else begin
					wordsNum <= dataRegQSpi[22:19]+dataRegQSpi[18:17]+dataRegQSpi[16]+dataRegQSpi[15]+dataRegQSpi[14]+dataRegQSpi[13:12]+dataRegQSpi[11:9]+dataRegQSpi[8:7];
				end 
			end
		end else begin
			wordsNum <= 0;
		end
	end 
	
	always @(posedge Clk_i) begin
		if (!Rst_i) begin
			ssReg <= Ss_i;
			ssRegR <= ssReg;
			ssRegRR <= ssRegR;
			ssPosR <= ssPos;
		end else begin
			ssReg <= 1;
			ssRegR <= 1;
			ssRegRR <= 1;
			ssPosR <= 0;
		end
	end 
	
	always @(posedge Clk_i) begin
		if (!Rst_i) begin
			if (ssPos) begin
				dataRegSSpi <= captRegSspi;
				dataRegQSpi <= {captReg0,captReg1,captReg2,captReg3};
				dataValReg <= 1'b1;
			end else begin
				dataValReg <= 1'b0;
			end
		end else begin
			dataRegSSpi <= 0;
			dataRegQSpi <= 0;
			dataValReg <= 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 (ssPosR)	begin
							nextState = DATARX;
						end	else begin
							nextState = IDLE;
						end
					end

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

endmodule



















