////////////////////////////////////////////////////////////////////////////////////////////
// Company:         TAIR
// Engineer:        Chigrinskiy A.  
// 
// Create Date:     18/04/2024 
// Design Name: 
// Module Name:     SPIm
// Project Name:    SB_TMSG44V1_FPGA
// Target Devices:  Board: SB_TMSG44v1. FPGA: GW1N-LV9PG256C6/I5
// Tool versions:
// Description:     This module implements SPI master interface
//
// Dependencies:  
// Revision: 
// Revision 1.0 - File Created
// Additional Comments: 
//
////////////////////////////////////////////////////////////////////////////////////////////
(* DONT_TOUCH = "true" *)
module QuadSpiMVariableWidth #(
    parameter DATA_MAX_WIDTH = 32
)(
    input Clk_i,
    input Rst_i,
    input Val_i,
    input [DATA_MAX_WIDTH-1:0] SpiData_i,
    input [6:0] WidthCurrent_i,

    output Ss_o,
    output  Mosi0_o,
    output  Mosi1_o,
    output  Mosi2_o,
    output  Mosi3_o,
    output Sck_o,
    output Busy_o
);

//================================================================================
//FUNCTIONS
//================================================================================
function integer log2;
input [31:0] value;
	begin
		log2 = 0;
		while (value > 1) begin
			value   = value >> 1;
			log2    = log2 + 1;
		end
		if	((2**log2)<DATA_MAX_WIDTH)	begin
			log2	=	log2+1;
		end	
	end
endfunction

//================================================================================
//	REG/WIRE
//================================================================================
localparam QSPI_MAX_WIDTH = DATA_MAX_WIDTH/4;

reg [log2(QSPI_MAX_WIDTH)-1:0] ssCnt;
reg [QSPI_MAX_WIDTH-1:0] mosiReg0;
reg [QSPI_MAX_WIDTH-1:0] mosiReg1;
reg [QSPI_MAX_WIDTH-1:0] mosiReg2;
reg [QSPI_MAX_WIDTH-1:0] mosiReg3;
reg	ssReg;

wire [7:0] shift;
wire [3:0] qSpiCntThreshold; 

//================================================================================
//  ASSIGNMENTS
//================================================================================
assign Ss_o = ssReg;

assign Mosi0_o = (!ssReg) ? mosiReg0[5] : 1'b0;
assign Mosi1_o = (!ssReg) ? mosiReg1[5] : 1'b0;
assign Mosi2_o = (!ssReg) ? mosiReg2[5] : 1'b0;
assign Mosi3_o = (!ssReg) ? mosiReg3[5] : 1'b0;

assign Sck_o = (!ssReg) ? Clk_i : 1'b0;
assign Busy_o = !ssReg;

assign shift = DATA_MAX_WIDTH - WidthCurrent_i;
assign qSpiShift = shift>>2;
assign qSpiCntThreshold = WidthCurrent_i>>2; 

//================================================================================
//	CODING
//================================================================================

always @(negedge Clk_i) begin 
    if (Rst_i) begin 
        ssCnt <= 7'h0;
    end
    else begin
        if (!ssReg) begin
			ssCnt <= ssCnt+1;
		end else begin
			ssCnt <= 0;
		end
    end
end

always @(negedge Clk_i) begin 
    if (Rst_i) begin 
        mosiReg0 <= 0;
        mosiReg1 <= 0;
        mosiReg2 <= 0;
        mosiReg3 <= 0;
    end
    else begin 
        if (!ssReg) begin 
            mosiReg0 <= mosiReg0 << 1;
            mosiReg1 <= mosiReg1 << 1;
            mosiReg2 <= mosiReg2 << 1;
            mosiReg3 <= mosiReg3 << 1;
        end
        else begin
            if (Val_i) begin
                mosiReg0 <= SpiData_i[23:18];
                mosiReg1 <= SpiData_i[17:12];
                mosiReg2 <= SpiData_i[11:6];
                mosiReg3 <= SpiData_i[5:0];
            end
        end
    end
end

always @(negedge Clk_i) begin 
    if (Rst_i) begin 
        ssReg <= 1'b1;
    end
    else begin 
        if (Val_i) begin
			ssReg <= 0;
		end
		if (ssCnt == qSpiCntThreshold-1) begin
			ssReg <= 1;
		end
    end
end

endmodule