`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 DataVal_o,
	output reg TestTrig_o,
	output [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 [OUTWORDWIDTH-1:0] captRegSspiR;
	reg [OUTWORDWIDTH-1:0] captRegSspiRR;

	reg [QSPIWORDWIDTH-1:0] captReg0R;
	reg [QSPIWORDWIDTH-1:0] captReg0RR;
	reg [QSPIWORDWIDTH-1:0] captReg1R;
	reg [QSPIWORDWIDTH-1:0] captReg1RR;
	reg [QSPIWORDWIDTH-1:0] captReg2R;
	reg [QSPIWORDWIDTH-1:0] captReg2RR;
	reg [QSPIWORDWIDTH-1:0] captReg3R;
	reg [QSPIWORDWIDTH-1:0] captReg3RR;

	reg ssReg;
	reg ssRegR;
	reg ssRegRR;
	
	reg spiMode;
	
	wire ssPos;
	reg ssPosR;
	
	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;

	wire plsToggleSyncSignal;
	reg plsToggle;
	reg plsToggleSyncA;
	reg plsToggleSyncB;
	reg plsToggleSyncC;
	reg plsToggleSyncSignalR;

//================================================================================
//  ASSIGNMENTS
	assign ssPos = ssRegR & !ssRegRR;

	
	assign DataVal_o = plsToggleSyncSignalR;
	assign Data_o = (spiMode)? dataRegQSpi:dataRegSSpi;

	assign plsToggleSyncSignal = plsToggleSyncB^plsToggleSyncA;

	//assign ssCntRstThresh = (spiMode) ? QSPIWORDWIDTH-1:SSPIWORDWIDTH-1;
	
//================================================================================
//  CODING

	always @(posedge Clk_i) begin 
    	if (Rst_i) begin 
    	    plsToggleSyncA <= 1'b0;
    	    plsToggleSyncB <= 1'b0;
    	end
    	else begin 
    	    plsToggleSyncA <= plsToggle;
    	    plsToggleSyncB <= plsToggleSyncA;
    	end
	end

	always @(posedge Clk_i) begin 
	    if (Rst_i) begin 
	        plsToggleSyncC <= 1'b0;
	    end
	    else begin
	        plsToggleSyncC <= plsToggleSyncB;
	    end
	end
	
	always @(posedge Ss_i or posedge Rst_i) begin 
		if (Rst_i) begin 
			plsToggle <= 1'b0;
		end
		else begin 
			if (Ss_i) begin 
				plsToggle <= ~plsToggle;
			end
			else begin 
				plsToggle <= plsToggle;
			end
		end
	end

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

	always @(posedge Sck_i or posedge Rst_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 @(posedge Clk_i) begin 
		if (Rst_i) begin 
			captRegSspiR <= 0;
			captRegSspiRR <= 0;
		end
		else begin 
			captRegSspiR <= captRegSspi;
			captRegSspiRR <= captRegSspiR;
		end
	end

	always @(posedge Clk_i) begin 
		if (Rst_i) begin 
			captReg0R <= 0;
			captReg0RR <= 0;
			captReg1R <= 0;
			captReg1RR <= 0;
			captReg2R <= 0;
			captReg2RR <= 0;
			captReg3R <= 0;
			captReg3RR <= 0;
		end
		else begin 
			captReg0R <= captReg0;
			captReg0RR <= captReg0R;
			captReg1R <= captReg1;
			captReg1RR <= captReg1R;
			captReg2R <= captReg2;
			captReg2RR <= captReg2R;
			captReg3R <= captReg3;
			captReg3RR <= captReg3R;
		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 Rst_i) begin 
		if (Rst_i) begin 
			ssCnt <= 0;
		end
		else begin 
			if (currState == IDLE) begin
				if (!Ss_i) begin 
					ssCnt <= ssCnt+1; 
				end
			end else begin
				ssCnt <= 0;
			end
		end
	end

	always @(posedge Clk_i) begin
		if (!Rst_i) begin
			if (currState == DATARX) begin
				if (plsToggleSyncSignal) 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 or posedge Rst_i) begin 
		if (Rst_i) begin 
			spiMode <= 1'b0;
		end
		else begin
			if (currState == IDLE) begin 
				if (ssCnt == 1) begin 
					if (captRegSspi[0]) begin 
						spiMode <= 1'b1; 
					end 
					else begin 
						spiMode <= 1'b0; 
					end
				end
			end
		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[21:19]+dataRegQSpi[17:16]+dataRegQSpi[15:12]+dataRegQSpi[11:9]+dataRegQSpi[7:6]+dataRegQSpi[4:3]+dataRegQSpi[2]+dataRegQSpi[1];
				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 (plsToggleSyncSignal) begin
				dataRegSSpi <= captRegSspiRR;
				dataRegQSpi <= {captReg0R,captReg1R,captReg2R,captReg3R};
				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 (plsToggleSyncSignalR)	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



















