module ExtSpiMEmul (
    input Clk_i,
    input Rst_i,
    input Start_i,
    input EmptyFlag_i,
    input ClockPhase_i,
    input [31:0] SpiData_i,
    input SelSt_i,
    input [1:0] WidthSel_i,
    input  Lag_i,
    input  Lead_i,
    input EndianSel_i,
    input [5:0] Stop_i,
    input PulsePol_i,


    output reg Mosi0_o,
    output reg Sck_o,
    output  Ss_o,
    output reg  Val_o
);


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

    reg startFlag;
    reg startR;
    reg [31:0] trCnt;
    reg valReg;
    reg valToRxFifo1;
    reg lineBusy;
    reg [5:0] ssCnt;
    reg Ss;
    reg [31:0]spiDataR;
    reg oldDataFlag;
    
    reg ssR;
    reg SSR;
    reg [31:0] mosiReg0;
    reg [5:0] ssNum;
    reg [2:0] delayCnt;
    reg stopFlag;
    
    wire ssPol = SelSt_i ? Ss : ~Ss;
    
    
    //================================================================================
    //  ASSIGNMENTS
    //================================================================================
    
    
    assign Ss_o = ssPol; 
    
    //================================================================================
    //	CODING
    //================================================================================
    
    always @(*) begin 
        if (Start_i) begin  
            Val_o = valReg;
        end
        else begin 
            Val_o = 1'b0;
        end
    end
    
    
    always @(*) begin 
        if (SelSt_i) begin 
            if (!Ss_o) begin 
                lineBusy = 1'b1;
            end
            else begin 
                lineBusy = 1'b0;
            end
        end
        else begin 
            if (Ss_o) begin 
                lineBusy = 1'b1;
            end
            else begin 
                lineBusy = 1'b0;
            end
        end
    end
    
    
    
    always @(posedge Clk_i) begin
        if (valReg) begin  
            spiDataR <= SpiData_i;
        end
    end
    
    
    always @(*) begin 
        if (Rst_i) begin 
            oldDataFlag = 1'b0;
        end
        else begin 
            if (spiDataR == SpiData_i && (SpiData_i != 0) || EmptyFlag_i) begin 
                oldDataFlag = 1'b1;
            end
            else begin 
                oldDataFlag = 1'b0;
            end
        end
    end
    
    
    always @(posedge Clk_i) begin 
        startR <= Start_i;
    end
    
    always @(*) begin 
        if (Rst_i) begin 
            valToRxFifo1 = 1'b0;
        end
        else begin 
            if (Start_i && !startR) begin 
                valToRxFifo1 = 1'b1;
            end
            else begin 
                valToRxFifo1 = 1'b0;
            end
        end
    end
    
    always @(negedge Clk_i) begin 
        if (Rst_i) begin 
            delayCnt <= 1'b0;
        end
        else begin 
            if (stopFlag &&delayCnt < Stop_i) begin 
                delayCnt <= delayCnt + 1'b1;
            end
            else begin 
                delayCnt <= 1'b0;
            end
        end
    end
    
    always @(posedge Clk_i) begin 
        if (Rst_i) begin 
            stopFlag <= 1'b0;
        end
        else begin
            if (SelSt_i) begin 
                if (ssPol && !ssR) begin 
                    stopFlag <= 1'b1;
                end
                else if ( delayCnt == Stop_i) begin 
                    stopFlag <= 1'b0;
                end
            end
            else begin 
                if (!ssPol && ssR) begin 
                    stopFlag <= 1'b1;
                end
                else if (delayCnt == Stop_i) begin 
                    stopFlag <= 1'b0;
                end
            end
        end
    end
    
    
    
    
    always @(*) begin
        if (SelSt_i) begin 
            if (PulsePol_i) begin 
                if (ClockPhase_i) begin
                    if (Lead_i == 0) begin 
                        if (!Ss && (ssCnt <= ssNum+Lag_i+Lead_i && ssCnt > Lag_i) ) begin 
                            Sck_o = ~(~Clk_i);
                        end
                        else begin 
                            Sck_o = 1'b0;
                        end
                    end
                    else begin 
                        if (!Ss && (ssCnt < ssNum+Lag_i+Lead_i && ssCnt > Lag_i)) begin 
                            Sck_o = ~(~Clk_i);
                        end
                        else begin 
                            Sck_o = 1'b0;
                        end
                    end
                end
                else begin
                    if (Lead_i == 0) begin 
                        if (!Ss && (ssCnt <= ssNum+Lag_i+Lead_i && ssCnt > Lag_i) ) begin 
                            Sck_o = ~(Clk_i);
                        end
                        else begin 
                            Sck_o = 1'b0;
                        end
                    end
                    else begin 
                        if (!Ss && (ssCnt < ssNum + Lag_i + Lead_i && ssCnt > Lag_i)) begin 
                            Sck_o = ~(Clk_i);
                        end
                        else begin 
                            Sck_o = 1'b0;
                        end
                    end
                end
            end
            else begin 
                if (ClockPhase_i) begin
                    if (Lead_i == 0) begin  
                        if (!Ss && (ssCnt <= ssNum+Lag_i+Lead_i && ssCnt > Lag_i) ) begin 
                            Sck_o = ~(Clk_i);
                        end
                        else begin 
                            Sck_o = 1'b0;
                        end
                    end
                    else begin 
                        if (!Ss && (ssCnt <ssNum + Lag_i + Lag_i && ssCnt > Lag_i)) begin 
                            Sck_o = ~(Clk_i);
                        end
                        else begin 
                            Sck_o = 1'b0;
                        end
                    end
                end 
                else begin
                    if (Lead_i == 0) begin 
                        if (!Ss && (ssCnt <= ssNum+Lag_i+Lead_i && ssCnt > Lag_i) ) begin 
                            Sck_o = ~(~Clk_i);
                        end
                        else begin 
                            Sck_o = 1'b0;
                        end
                    end
                    else begin 
                        if (!Ss && (ssCnt < ssNum + Lag_i + Lead_i && ssCnt > Lag_i)) begin 
                            Sck_o = ~(~Clk_i);
                        end
                        else begin 
                            Sck_o = 1'b0;
                        end
                    end
                end
            end
        end
        else begin 
              if (PulsePol_i) begin 
                if (ClockPhase_i) begin
                    if (Lead_i == 0) begin 
                        if (ssPol && (ssCnt <= ssNum+Lag_i+Lead_i && ssCnt > Lag_i) ) begin 
                            Sck_o = ~(~Clk_i);
                        end
                        else begin 
                            Sck_o = 1'b0;
                        end
                    end
                    else begin 
                        if (ssPol && (ssCnt < ssNum+Lag_i+Lead_i && ssCnt > Lag_i)) begin 
                            Sck_o = ~(~Clk_i);
                        end
                        else begin 
                            Sck_o = 1'b0;
                        end
                    end
                end
                else begin
                    if (Lead_i == 0) begin 
                        if (ssPol && (ssCnt <= ssNum+Lag_i+Lead_i && ssCnt > Lag_i) ) begin 
                            Sck_o = ~(Clk_i);
                        end
                        else begin 
                            Sck_o = 1'b0;
                        end
                    end
                    else begin 
                        if (ssPol && (ssCnt < ssNum + Lag_i + Lead_i && ssCnt > Lag_i)) begin 
                            Sck_o = ~(Clk_i);
                        end
                        else begin 
                            Sck_o = 1'b0;
                        end
                    end
                end
            end
            else begin 
                if (ClockPhase_i) begin
                    if (Lead_i == 0) begin  
                        if (ssPol && (ssCnt <= ssNum+Lag_i+Lead_i && ssCnt > Lag_i) ) begin 
                            Sck_o = ~(Clk_i);
                        end
                        else begin 
                            Sck_o = 1'b0;
                        end
                    end
                    else begin 
                        if (ssPol && (ssCnt <ssNum + Lag_i + Lag_i && ssCnt > Lag_i)) begin 
                            Sck_o = ~(Clk_i);
                        end
                        else begin 
                            Sck_o = 1'b0;
                        end
                    end
                end 
                else begin
                    if (Lead_i == 0) begin 
                        if (ssPol && (ssCnt <= ssNum+Lag_i+Lead_i && ssCnt > Lag_i) ) begin 
                            Sck_o = ~(~Clk_i);
                        end
                        else begin 
                            Sck_o = 1'b0;
                        end
                    end
                    else begin 
                        if (ssPol && (ssCnt < ssNum + Lag_i + Lead_i && ssCnt > Lag_i)) begin 
                            Sck_o = ~(~Clk_i);
                        end
                        else begin 
                            Sck_o = 1'b0;
                        end
                    end
                end
            end
        end
            
    end
    
    
    always @(*) begin
        if (Rst_i) begin 
            Mosi0_o = 1'b0;
        end
        else begin
            if (SelSt_i) begin 
                if (!EndianSel_i) begin 
                    case (WidthSel_i)  
                        0 : begin
                            Mosi0_o = (!Ss&& (ssCnt <= ssNum+Lag_i && ssCnt > Lag_i))? (mosiReg0[7]):1'b0;
                        end
                        1 : begin
                            Mosi0_o = (!Ss&& (ssCnt <= ssNum+Lag_i && ssCnt > Lag_i))? (mosiReg0[15]):1'b0;
                        end
                        2 : begin
                            Mosi0_o = (!Ss&& (ssCnt <= ssNum+Lag_i && ssCnt > Lag_i))? (mosiReg0[23]):1'b0;
                        end
                        3 : begin
                            Mosi0_o = (!Ss&& (ssCnt <= ssNum+Lag_i && ssCnt > Lag_i))? (mosiReg0[31]):1'b0;
                        end
                    endcase
                end
                else begin 
                    case (WidthSel_i)  
                        0 : begin
                            Mosi0_o = (!Ss&& (ssCnt <= ssNum+Lag_i && ssCnt > Lag_i))? (mosiReg0[0]):1'b0;
                        end
                        1 : begin
                            Mosi0_o = (!Ss&& (ssCnt <= ssNum+Lag_i && ssCnt > Lag_i))? (mosiReg0[0]):1'b0;
                        end
                        2 : begin
                            Mosi0_o = (!Ss&& (ssCnt <= ssNum+Lag_i && ssCnt > Lag_i))? (mosiReg0[0]):1'b0;
                        end
                        3 : begin
                            Mosi0_o = (!Ss&& (ssCnt <= ssNum+Lag_i && ssCnt > Lag_i))? (mosiReg0[0]):1'b0;
                        end
                    endcase
                end
            end
            else begin 
                if (!EndianSel_i) begin 
                    case (WidthSel_i)  
                        0 : begin
                            Mosi0_o = (ssPol&& (ssCnt <= ssNum+Lag_i && ssCnt > Lag_i))? (mosiReg0[7]):1'b0;
                        end
                        1 : begin
                            Mosi0_o = (ssPol&& (ssCnt <= ssNum+Lag_i && ssCnt > Lag_i))? (mosiReg0[15]):1'b0;
                        end
                        2 : begin
                            Mosi0_o = (ssPol&& (ssCnt <= ssNum+Lag_i && ssCnt > Lag_i))? (mosiReg0[23]):1'b0;
                        end
                        3 : begin
                            Mosi0_o = (ssPol&& (ssCnt <= ssNum+Lag_i && ssCnt > Lag_i))? (mosiReg0[31]):1'b0;
                        end
                    endcase
                end
                else begin 
                    case (WidthSel_i)  
                        0 : begin
                            Mosi0_o = (ssPol&& (ssCnt <= ssNum+Lag_i && ssCnt > Lag_i))? (mosiReg0[0]):1'b0;
                        end
                        1 : begin
                            Mosi0_o = (ssPol&& (ssCnt <= ssNum+Lag_i && ssCnt > Lag_i))? (mosiReg0[0]):1'b0;
                        end
                        2 : begin
                            Mosi0_o = (ssPol&& (ssCnt <= ssNum+Lag_i && ssCnt > Lag_i))? (mosiReg0[0]):1'b0;
                        end
                        3 : begin
                            Mosi0_o = (ssPol&& (ssCnt <= ssNum+Lag_i && ssCnt > Lag_i))? (mosiReg0[0]):1'b0;
                        end
                    endcase
                end
            end
        end
    end
    
    
    
    always @(posedge Clk_i) begin
        ssR <= ssPol;
        SSR <= Ss;
    end
    
    
    always @(*) begin 
        if (Rst_i) begin 
            startFlag = 1'b0;
        end
        else begin 
            if (Start_i && !stopFlag && !EmptyFlag_i) begin 
                startFlag = 1'b1;
            end
            else begin 
                startFlag = 1'b0;
            end
        end
    end
    
    always @(*) begin
        if (SelSt_i) begin 
            if (Ss_o && !ssR) begin 
                valReg = 1'b1;
            end
            else begin 
                valReg = 1'b0;
            end
        end
        else begin 
            if (!Ss_o&& ssR) begin 
                valReg = 1'b1;
            end
            else begin 
                valReg = 1'b0;
            end
        end
    end
    
    
    always @(*) begin 
        if (Rst_i) begin 
            ssNum = 1'b0;
        end
        else begin 
            case (WidthSel_i) 
                0 : begin 
                    ssNum = 8;
                end
                1 : begin 
                    ssNum = 16;
                end
                2 : begin 
                    ssNum = 24;
                end
                3 : begin 
                    ssNum = 32;
                end
            endcase
        end
    end
    
    
    always @(negedge Clk_i) begin 
        if (Rst_i) begin 
            ssCnt <= 1'b0;
        end
        else if (ssCnt <= (ssNum+Lag_i+Lead_i)  && startFlag  ) begin 
            ssCnt <= ssCnt + 1'b1;
        end
        else begin
            if (ssCnt == ssNum-1 || !startFlag) begin 
                ssCnt <= 1'b0;
            end
        end
    end
    
    
    
    
    always @(negedge Clk_i) begin 
        if (Rst_i) begin 
            Ss <= 1'b1;
        end
        else begin 
            if (ssCnt <= (ssNum+Lag_i+Lead_i)  && startFlag ) begin 
                Ss <= 1'b0;
            end
            else begin 
                Ss <= 1'b1;
            end
        end
    end
    
    
    always @(negedge Clk_i) begin 
        if (Rst_i) begin 
            mosiReg0 <= SpiData_i[31:0];
        end
        else begin
            if (!EndianSel_i) begin 
                if (!SSR && (ssCnt > Lag_i && ssCnt < ssNum + Lag_i + Lead_i)) begin
                    mosiReg0 <= mosiReg0 << 1;
                end
                else begin 
                    mosiReg0 <= SpiData_i[31:0];
                end
            end
            else begin 
                if (!SSR && (ssCnt > Lag_i && ssCnt < ssNum + Lag_i + Lead_i)) begin
                    mosiReg0 <= mosiReg0 >> 1;
                end
                else begin 
                    mosiReg0 <= SpiData_i[31:0];
                end
            end
        end
    end
    
    
    
    
    
    
    
    endmodule