////////////////////////////////////////////////////////////////////////////////////////////
// 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: 
//
////////////////////////////////////////////////////////////////////////////////////////////
module SpiM #(
    parameter DATA_WIDTH = 24,
    parameter CS_DELAY = 3'h0,
    parameter IS_LMX_DELAY = 0
)(
    input Clk_i,
    input Rst_i,
    input Val_i,
    input [DATA_WIDTH-1:0] SpiData_i,

    output Ss_o,
    output Mosi_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_WIDTH)	begin
			log2	=	log2+1;
		end	
	end
endfunction

//================================================================================
//	REG/WIRE
//================================================================================
reg [log2(DATA_WIDTH)-1:0] ssCnt;
reg [2:0] ssCntDelay;
reg [DATA_WIDTH-1:0] mosiReg;
reg	ssReg;
//================================================================================
//  ASSIGNMENTS
//================================================================================
assign Ss_o = ssReg;
generate 
    if (IS_LMX_DELAY) begin 
        assign Sck_o = (!ssReg && ssCnt < DATA_WIDTH && (ssCntDelay == 0)) ? Clk_i : 1'b0;
        assign Mosi_o = (!ssReg && ssCnt < DATA_WIDTH && (ssCntDelay == 0)) ? mosiReg[DATA_WIDTH-1] : 1'b0;
    end
    else begin 
        assign Sck_o = (!ssReg) ? Clk_i : 1'b0;
        assign Mosi_o = (!ssReg) ? mosiReg[DATA_WIDTH-1] : 1'b0;
    end
endgenerate

assign Busy_o = !ssReg;

//================================================================================
//	CODING
//================================================================================
generate
    if (IS_LMX_DELAY) begin
        always @(negedge Clk_i) begin 
            if (Rst_i) begin 
                ssCnt <= 7'h0;
            end
            else begin 
                if (!ssReg ) begin 
                    if (ssCntDelay == 3'h0) begin
                        ssCnt <= ssCnt + 1;
                    end
                end
                else begin
                    ssCnt <= 0;
                end
            end
        end
		
        always @(negedge Clk_i) begin 
         	if (Rst_i) begin 
            	ssCntDelay <= 3'h0;
         	end
         	else begin
            	if (ssReg) begin
					ssCntDelay <= CS_DELAY;
				end
				else begin
					if (ssCntDelay != 3'h0) begin
						ssCntDelay <= ssCntDelay - 1;
					end
				end
         	end
        end

        always @(negedge Clk_i) begin 
            if (Rst_i) begin 
                mosiReg <= 0;
            end
            else begin 
                if ((!ssReg) && (ssCntDelay == 3'h0)) begin 
                    mosiReg <= mosiReg << 1;
                end
                else begin
                    if (Val_i) begin
                        mosiReg <= SpiData_i;
                    end
                end
            end
        end
    end
    else begin
        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 
				ssCntDelay <= 3'h0;
			end
			else begin
				ssCntDelay <= 3'h0;
			end
		end
        always @(negedge Clk_i) begin 
            if (Rst_i) begin 
                mosiReg <= 0;
            end
            else begin 
                if (!ssReg) begin 
                    mosiReg <= mosiReg << 1;
                end
                else begin
                    if (Val_i) begin
                        mosiReg <= SpiData_i;
                    end
                end
            end
        end
    end
endgenerate

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

endmodule